| 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 13 matching lines...) Expand all Loading... |
| 24 #include "webrtc/modules/desktop_capture/desktop_capture_options.h" | 24 #include "webrtc/modules/desktop_capture/desktop_capture_options.h" |
| 25 #include "webrtc/modules/desktop_capture/desktop_frame.h" | 25 #include "webrtc/modules/desktop_capture/desktop_frame.h" |
| 26 #include "webrtc/modules/desktop_capture/x11/shared_x_display.h" | 26 #include "webrtc/modules/desktop_capture/x11/shared_x_display.h" |
| 27 #include "webrtc/modules/desktop_capture/x11/x_error_trap.h" | 27 #include "webrtc/modules/desktop_capture/x11/x_error_trap.h" |
| 28 #include "webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h" | 28 #include "webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h" |
| 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 const uint32_t kAlphaMask = 0xFF000000; |
| 35 const uint32_t kRedMask = 0x00FF0000; |
| 36 const uint32_t kGreenMask = 0x0000FF00; |
| 37 const uint32_t kBlueMask = 0x000000FF; |
| 38 |
| 39 const int kAlphaShift = 24; |
| 40 const int kRedShift = 16; |
| 41 const int kGreenShift = 8; |
| 42 const int kBlueShift = 0; |
| 43 |
| 44 uint32_t MultiplyAlpha(uint32_t raw_color_component, uint32_t alpha) { |
| 45 uint32_t product = raw_color_component * alpha + 128; |
| 46 return (product + (product >> 8)) >> 8; |
| 47 } |
| 48 |
| 49 // Convert a raw ARGB color pixel into a premultiplied ARGB color |
| 50 uint32_t PremultipliedColor(uint32_t raw_color) { |
| 51 uint32_t alpha, red, green, blue; |
| 52 alpha = (raw_color & kAlphaMask) >> kAlphaShift; |
| 53 red = (raw_color & kRedMask) >> kRedShift; |
| 54 green = (raw_color & kGreenMask) >> kGreenShift; |
| 55 blue = (raw_color & kBlueMask) >> kBlueShift; |
| 56 |
| 57 red = MultiplyAlpha(red, alpha); |
| 58 green = MultiplyAlpha(green, alpha); |
| 59 blue = MultiplyAlpha(blue, alpha); |
| 60 |
| 61 return (alpha << kAlphaShift) | (red << kRedShift) | (green << kGreenShift) | |
| 62 (blue << kBlueShift); |
| 63 } |
| 34 | 64 |
| 35 // Convenience wrapper for XGetWindowProperty() results. | 65 // Convenience wrapper for XGetWindowProperty() results. |
| 36 template <class PropertyType> | 66 template <class PropertyType> |
| 37 class XWindowProperty { | 67 class XWindowProperty { |
| 38 public: | 68 public: |
| 39 XWindowProperty(Display* display, Window window, Atom property) { | 69 XWindowProperty(Display* display, Window window, Atom property) { |
| 40 const int kBitsPerByte = 8; | 70 const int kBitsPerByte = 8; |
| 41 Atom actual_type; | 71 Atom actual_type; |
| 42 int actual_format; | 72 int actual_format; |
| 43 unsigned long bytes_after; // NOLINT: type required by XGetWindowProperty | 73 unsigned long bytes_after; // NOLINT: type required by XGetWindowProperty |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 107 // that has WM_STATE property set to NormalState. | 137 // that has WM_STATE property set to NormalState. |
| 108 // See http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.3.1 . | 138 // See http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.3.1 . |
| 109 ::Window GetApplicationWindow(::Window window); | 139 ::Window GetApplicationWindow(::Window window); |
| 110 | 140 |
| 111 // Returns true if the |window| is a desktop element. | 141 // Returns true if the |window| is a desktop element. |
| 112 bool IsDesktopElement(::Window window); | 142 bool IsDesktopElement(::Window window); |
| 113 | 143 |
| 114 // Returns window title for the specified X |window|. | 144 // Returns window title for the specified X |window|. |
| 115 bool GetWindowTitle(::Window window, std::string* title); | 145 bool GetWindowTitle(::Window window, std::string* title); |
| 116 | 146 |
| 147 std::unique_ptr<DesktopFrame> GetWindowIcon(::Window window); |
| 148 |
| 117 Callback* callback_ = nullptr; | 149 Callback* callback_ = nullptr; |
| 118 | 150 |
| 119 rtc::scoped_refptr<SharedXDisplay> x_display_; | 151 rtc::scoped_refptr<SharedXDisplay> x_display_; |
| 120 | 152 |
| 121 Atom wm_state_atom_; | 153 Atom wm_state_atom_; |
| 122 Atom window_type_atom_; | 154 Atom window_type_atom_; |
| 123 Atom normal_window_type_atom_; | 155 Atom normal_window_type_atom_; |
| 156 Atom icon_atom_; |
| 124 bool has_composite_extension_ = false; | 157 bool has_composite_extension_ = false; |
| 125 | 158 |
| 126 ::Window selected_window_ = 0; | 159 ::Window selected_window_ = 0; |
| 127 XServerPixelBuffer x_server_pixel_buffer_; | 160 XServerPixelBuffer x_server_pixel_buffer_; |
| 128 | 161 |
| 129 RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerLinux); | 162 RTC_DISALLOW_COPY_AND_ASSIGN(WindowCapturerLinux); |
| 130 }; | 163 }; |
| 131 | 164 |
| 132 WindowCapturerLinux::WindowCapturerLinux(const DesktopCaptureOptions& options) | 165 WindowCapturerLinux::WindowCapturerLinux(const DesktopCaptureOptions& options) |
| 133 : x_display_(options.x_display()) { | 166 : x_display_(options.x_display()) { |
| 134 // Create Atoms so we don't need to do it every time they are used. | 167 // Create Atoms so we don't need to do it every time they are used. |
| 135 wm_state_atom_ = XInternAtom(display(), "WM_STATE", True); | 168 wm_state_atom_ = XInternAtom(display(), "WM_STATE", True); |
| 136 window_type_atom_ = XInternAtom(display(), "_NET_WM_WINDOW_TYPE", True); | 169 window_type_atom_ = XInternAtom(display(), "_NET_WM_WINDOW_TYPE", True); |
| 137 normal_window_type_atom_ = XInternAtom( | 170 normal_window_type_atom_ = XInternAtom( |
| 138 display(), "_NET_WM_WINDOW_TYPE_NORMAL", True); | 171 display(), "_NET_WM_WINDOW_TYPE_NORMAL", True); |
| 172 icon_atom_ = XInternAtom(display(), "_NET_WM_ICON", True); |
| 139 | 173 |
| 140 int event_base, error_base, major_version, minor_version; | 174 int event_base, error_base, major_version, minor_version; |
| 141 if (XCompositeQueryExtension(display(), &event_base, &error_base) && | 175 if (XCompositeQueryExtension(display(), &event_base, &error_base) && |
| 142 XCompositeQueryVersion(display(), &major_version, &minor_version) && | 176 XCompositeQueryVersion(display(), &major_version, &minor_version) && |
| 143 // XCompositeNameWindowPixmap() requires version 0.2 | 177 // XCompositeNameWindowPixmap() requires version 0.2 |
| 144 (major_version > 0 || minor_version >= 2)) { | 178 (major_version > 0 || minor_version >= 2)) { |
| 145 has_composite_extension_ = true; | 179 has_composite_extension_ = true; |
| 146 } else { | 180 } else { |
| 147 LOG(LS_INFO) << "Xcomposite extension not available or too old."; | 181 LOG(LS_INFO) << "Xcomposite extension not available or too old."; |
| 148 } | 182 } |
| 149 | 183 |
| 150 x_display_->AddEventHandler(ConfigureNotify, this); | 184 x_display_->AddEventHandler(ConfigureNotify, this); |
| 151 } | 185 } |
| 152 | 186 |
| 153 WindowCapturerLinux::~WindowCapturerLinux() { | 187 WindowCapturerLinux::~WindowCapturerLinux() { |
| 154 x_display_->RemoveEventHandler(ConfigureNotify, this); | 188 x_display_->RemoveEventHandler(ConfigureNotify, this); |
| 155 } | 189 } |
| 156 | 190 |
| 157 bool WindowCapturerLinux::GetWindowList(WindowList* windows) { | 191 bool WindowCapturerLinux::GetWindowList(WindowList* windows) { |
| 158 WindowList result; | 192 windows->clear(); |
| 159 | |
| 160 XErrorTrap error_trap(display()); | 193 XErrorTrap error_trap(display()); |
| 161 | 194 |
| 162 int num_screens = XScreenCount(display()); | 195 int num_screens = XScreenCount(display()); |
| 163 for (int screen = 0; screen < num_screens; ++screen) { | 196 for (int screen = 0; screen < num_screens; ++screen) { |
| 164 ::Window root_window = XRootWindow(display(), screen); | 197 ::Window root_window = XRootWindow(display(), screen); |
| 165 ::Window parent; | 198 ::Window parent; |
| 166 ::Window *children; | 199 ::Window *children; |
| 167 unsigned int num_children; | 200 unsigned int num_children; |
| 168 int status = XQueryTree(display(), root_window, &root_window, &parent, | 201 int status = XQueryTree(display(), root_window, &root_window, &parent, |
| 169 &children, &num_children); | 202 &children, &num_children); |
| 170 if (status == 0) { | 203 if (status == 0) { |
| 171 LOG(LS_ERROR) << "Failed to query for child windows for screen " | 204 LOG(LS_ERROR) << "Failed to query for child windows for screen " |
| 172 << screen; | 205 << screen; |
| 173 continue; | 206 continue; |
| 174 } | 207 } |
| 175 | 208 |
| 176 for (unsigned int i = 0; i < num_children; ++i) { | 209 for (unsigned int i = 0; i < num_children; ++i) { |
| 177 // Iterate in reverse order to return windows from front to back. | 210 // Iterate in reverse order to return windows from front to back. |
| 178 ::Window app_window = | 211 ::Window app_window = |
| 179 GetApplicationWindow(children[num_children - 1 - i]); | 212 GetApplicationWindow(children[num_children - 1 - i]); |
| 180 if (app_window && !IsDesktopElement(app_window)) { | 213 if (app_window && !IsDesktopElement(app_window)) { |
| 181 Window w; | 214 Window w; |
| 182 w.id = app_window; | 215 w.id = app_window; |
| 183 if (GetWindowTitle(app_window, &w.title)) | 216 if (!GetWindowTitle(app_window, &w.title)) |
| 184 result.push_back(w); | 217 continue; |
| 218 w.icon = GetWindowIcon(app_window); |
| 219 windows->push_back(std::move(w)); |
| 185 } | 220 } |
| 186 } | 221 } |
| 187 | 222 |
| 188 if (children) | 223 if (children) |
| 189 XFree(children); | 224 XFree(children); |
| 190 } | 225 } |
| 191 | 226 |
| 192 windows->swap(result); | |
| 193 | |
| 194 return true; | 227 return true; |
| 195 } | 228 } |
| 196 | 229 |
| 197 bool WindowCapturerLinux::SelectWindow(WindowId id) { | 230 bool WindowCapturerLinux::SelectWindow(WindowId id) { |
| 198 if (!x_server_pixel_buffer_.Init(display(), id)) | 231 if (!x_server_pixel_buffer_.Init(display(), id)) |
| 199 return false; | 232 return false; |
| 200 | 233 |
| 201 // Tell the X server to send us window resizing events. | 234 // Tell the X server to send us window resizing events. |
| 202 XSelectInput(display(), id, StructureNotifyMask); | 235 XSelectInput(display(), id, StructureNotifyMask); |
| 203 | 236 |
| (...skipping 207 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 411 } | 444 } |
| 412 if (list) | 445 if (list) |
| 413 XFreeStringList(list); | 446 XFreeStringList(list); |
| 414 } | 447 } |
| 415 if (window_name.value) | 448 if (window_name.value) |
| 416 XFree(window_name.value); | 449 XFree(window_name.value); |
| 417 } | 450 } |
| 418 return result; | 451 return result; |
| 419 } | 452 } |
| 420 | 453 |
| 454 std::unique_ptr<DesktopFrame> WindowCapturerLinux::GetWindowIcon( |
| 455 ::Window window) { |
| 456 XWindowProperty<uint32_t> icon_property(display(), window, icon_atom_); |
| 457 |
| 458 long* data = (long*)icon_property.data(); |
| 459 |
| 460 uint32_t length = icon_property.size(); |
| 461 if (length == 0) |
| 462 return nullptr; |
| 463 |
| 464 long width, height; |
| 465 int start = 0; |
| 466 uint32_t i = 0; |
| 467 while (i < length) { |
| 468 if (i == 0 || data[i] * data[i + 1] > width * height) { |
| 469 width = data[i]; |
| 470 height = data[i + 1]; |
| 471 start = i + 2; |
| 472 } |
| 473 i = i + 2 + data[i] * data[i + 1]; |
| 474 } |
| 475 |
| 476 std::unique_ptr<DesktopFrame> frame( |
| 477 new BasicDesktopFrame(DesktopSize(width, height))); |
| 478 |
| 479 uint32_t* frame_data = (uint32_t*)frame->data(); |
| 480 int dest_int_stride = frame->stride() / sizeof(uint32_t); |
| 481 for (int y = 0; y < height; ++y) { |
| 482 for (int x = 0; x < width; ++x) { |
| 483 frame_data[y * dest_int_stride + x] = PremultipliedColor( |
| 484 static_cast<uint32_t>(data[start + y * width + x])); |
| 485 } |
| 486 } |
| 487 |
| 488 frame->mutable_updated_region()->SetRect( |
| 489 DesktopRect::MakeSize(frame->size())); |
| 490 |
| 491 return frame; |
| 492 } |
| 493 |
| 421 } // namespace | 494 } // namespace |
| 422 | 495 |
| 423 // static | 496 // static |
| 424 WindowCapturer* WindowCapturer::Create(const DesktopCaptureOptions& options) { | 497 WindowCapturer* WindowCapturer::Create(const DesktopCaptureOptions& options) { |
| 425 if (!options.x_display()) | 498 if (!options.x_display()) |
| 426 return nullptr; | 499 return nullptr; |
| 427 return new WindowCapturerLinux(options); | 500 return new WindowCapturerLinux(options); |
| 428 } | 501 } |
| 429 | 502 |
| 430 } // namespace webrtc | 503 } // namespace webrtc |
| OLD | NEW |