1e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org/* 2e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org * 4e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org * Use of this source code is governed by a BSD-style license 5e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org * that can be found in the LICENSE file in the root of the source 6e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org * tree. An additional intellectual property rights grant can be found 7e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org * in the file PATENTS. All contributing project authors may 8e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org * be found in the AUTHORS file in the root of the source tree. 9e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org */ 10e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 11e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org#include "webrtc/modules/desktop_capture/window_capturer.h" 12e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 13bcf0a1019f34cac346bd8349c2206f9d06adbe4epbos@webrtc.org#include <assert.h> 14e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org#include <string.h> 15e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org#include <X11/Xatom.h> 16e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org#include <X11/extensions/Xcomposite.h> 17e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org#include <X11/extensions/Xrender.h> 18e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org#include <X11/Xutil.h> 19bcf0a1019f34cac346bd8349c2206f9d06adbe4epbos@webrtc.org 20e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org#include <algorithm> 21e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 2291685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org#include "webrtc/modules/desktop_capture/desktop_capture_options.h" 23e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org#include "webrtc/modules/desktop_capture/desktop_frame.h" 2491685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org#include "webrtc/modules/desktop_capture/x11/shared_x_display.h" 25e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org#include "webrtc/modules/desktop_capture/x11/x_error_trap.h" 26e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org#include "webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h" 27e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org#include "webrtc/system_wrappers/interface/logging.h" 28e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org#include "webrtc/system_wrappers/interface/scoped_ptr.h" 2991685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org#include "webrtc/system_wrappers/interface/scoped_refptr.h" 30e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 31e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.orgnamespace webrtc { 32e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 33e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.orgnamespace { 34e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 35e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org// Convenience wrapper for XGetWindowProperty() results. 36e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.orgtemplate <class PropertyType> 37e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.orgclass XWindowProperty { 38e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org public: 39e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org XWindowProperty(Display* display, Window window, Atom property) 40e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org : is_valid_(false), 41e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org size_(0), 42e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org data_(NULL) { 43e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org const int kBitsPerByte = 8; 44e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org Atom actual_type; 45e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org int actual_format; 46e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org unsigned long bytes_after; // NOLINT: type required by XGetWindowProperty 47e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org int status = XGetWindowProperty(display, window, property, 0L, ~0L, False, 48e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org AnyPropertyType, &actual_type, 49e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org &actual_format, &size_, 50e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org &bytes_after, &data_); 51e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (status != Success) { 52e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org data_ = NULL; 53e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org return; 54e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 55e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (sizeof(PropertyType) * kBitsPerByte != actual_format) { 56e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org size_ = 0; 57e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org return; 58e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 59e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 60e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org is_valid_ = true; 61e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 62e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 63e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org ~XWindowProperty() { 64e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (data_) 65e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org XFree(data_); 66e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 67e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 68e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // True if we got properly value successfully. 69e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org bool is_valid() const { return is_valid_; } 70e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 71e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // Size and value of the property. 72e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org size_t size() const { return size_; } 73e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org const PropertyType* data() const { 74e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org return reinterpret_cast<PropertyType*>(data_); 75e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 76e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org PropertyType* data() { 77e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org return reinterpret_cast<PropertyType*>(data_); 78e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 79e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 80e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org private: 81e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org bool is_valid_; 82e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org unsigned long size_; // NOLINT: type required by XGetWindowProperty 83e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org unsigned char* data_; 84e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 85e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org DISALLOW_COPY_AND_ASSIGN(XWindowProperty); 86e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org}; 87e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 88ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.orgclass WindowCapturerLinux : public WindowCapturer, 89ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org public SharedXDisplay::XEventHandler { 90e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org public: 9191685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org WindowCapturerLinux(const DesktopCaptureOptions& options); 92e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org virtual ~WindowCapturerLinux(); 93e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 94e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // WindowCapturer interface. 95e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org virtual bool GetWindowList(WindowList* windows) OVERRIDE; 96e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org virtual bool SelectWindow(WindowId id) OVERRIDE; 97dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org virtual bool BringSelectedWindowToFront() OVERRIDE; 98e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 99e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // DesktopCapturer interface. 100e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org virtual void Start(Callback* callback) OVERRIDE; 101e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org virtual void Capture(const DesktopRegion& region) OVERRIDE; 102e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 103ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org // SharedXDisplay::XEventHandler interface. 104ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org virtual bool HandleXEvent(const XEvent& event) OVERRIDE; 105ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org 106e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org private: 10791685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org Display* display() { return x_display_->display(); } 10891685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org 109e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // Iterates through |window| hierarchy to find first visible window, i.e. one 110e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // that has WM_STATE property set to NormalState. 111e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // See http://tronche.com/gui/x/icccm/sec-4.html#s-4.1.3.1 . 112e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org ::Window GetApplicationWindow(::Window window); 113e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 114e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // Returns true if the |window| is a desktop element. 115e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org bool IsDesktopElement(::Window window); 116e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 117e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // Returns window title for the specified X |window|. 118e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org bool GetWindowTitle(::Window window, std::string* title); 119e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 120e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org Callback* callback_; 121e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 12291685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org scoped_refptr<SharedXDisplay> x_display_; 123e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 124e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org Atom wm_state_atom_; 125e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org Atom window_type_atom_; 126e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org Atom normal_window_type_atom_; 127e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org bool has_composite_extension_; 128e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 129e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org ::Window selected_window_; 130e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org XServerPixelBuffer x_server_pixel_buffer_; 131e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 132e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org DISALLOW_COPY_AND_ASSIGN(WindowCapturerLinux); 133e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org}; 134e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 13591685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.orgWindowCapturerLinux::WindowCapturerLinux(const DesktopCaptureOptions& options) 136e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org : callback_(NULL), 13791685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org x_display_(options.x_display()), 138e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org has_composite_extension_(false), 139e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org selected_window_(0) { 140e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // Create Atoms so we don't need to do it every time they are used. 14191685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org wm_state_atom_ = XInternAtom(display(), "WM_STATE", True); 14291685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org window_type_atom_ = XInternAtom(display(), "_NET_WM_WINDOW_TYPE", True); 143e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org normal_window_type_atom_ = XInternAtom( 14491685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org display(), "_NET_WM_WINDOW_TYPE_NORMAL", True); 145e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 146e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org int event_base, error_base, major_version, minor_version; 14791685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org if (XCompositeQueryExtension(display(), &event_base, &error_base) && 14891685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org XCompositeQueryVersion(display(), &major_version, &minor_version) && 149e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // XCompositeNameWindowPixmap() requires version 0.2 150e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org (major_version > 0 || minor_version >= 2)) { 151e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org has_composite_extension_ = true; 152e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } else { 153e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org LOG(LS_INFO) << "Xcomposite extension not available or too old."; 154e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 155ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org 156ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org x_display_->AddEventHandler(ConfigureNotify, this); 157e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org} 158e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 159ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.orgWindowCapturerLinux::~WindowCapturerLinux() { 160ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org x_display_->RemoveEventHandler(ConfigureNotify, this); 161ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org} 162e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 163e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.orgbool WindowCapturerLinux::GetWindowList(WindowList* windows) { 164e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org WindowList result; 165e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 16691685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org XErrorTrap error_trap(display()); 167e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 16891685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org int num_screens = XScreenCount(display()); 169e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org for (int screen = 0; screen < num_screens; ++screen) { 17091685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org ::Window root_window = XRootWindow(display(), screen); 171e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org ::Window parent; 172e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org ::Window *children; 173e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org unsigned int num_children; 17491685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org int status = XQueryTree(display(), root_window, &root_window, &parent, 175e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org &children, &num_children); 176e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (status == 0) { 177e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org LOG(LS_ERROR) << "Failed to query for child windows for screen " 178e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org << screen; 179e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org continue; 180e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 181e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 182e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org for (unsigned int i = 0; i < num_children; ++i) { 183e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // Iterate in reverse order to return windows from front to back. 184e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org ::Window app_window = 185e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org GetApplicationWindow(children[num_children - 1 - i]); 186e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (app_window && !IsDesktopElement(app_window)) { 187e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org Window w; 188e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org w.id = app_window; 189e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (GetWindowTitle(app_window, &w.title)) 190e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org result.push_back(w); 191e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 192e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 193e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 194e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (children) 195e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org XFree(children); 196e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 197e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 198e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org windows->swap(result); 199e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 200e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org return true; 201e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org} 202e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 203e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.orgbool WindowCapturerLinux::SelectWindow(WindowId id) { 20491685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org if (!x_server_pixel_buffer_.Init(display(), id)) 205e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org return false; 206e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 207ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org // Tell the X server to send us window resizing events. 208ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org XSelectInput(display(), id, StructureNotifyMask); 209ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org 210e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org selected_window_ = id; 211e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 212e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // In addition to needing X11 server-side support for Xcomposite, it actually 213e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // needs to be turned on for the window. If the user has modern 214e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // hardware/drivers but isn't using a compositing window manager, that won't 215e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // be the case. Here we automatically turn it on. 216e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 217e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // Redirect drawing to an offscreen buffer (ie, turn on compositing). X11 218e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // remembers who has requested this and will turn it off for us when we exit. 21991685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org XCompositeRedirectWindow(display(), id, CompositeRedirectAutomatic); 220e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 221e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org return true; 222e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org} 223e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 224dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.orgbool WindowCapturerLinux::BringSelectedWindowToFront() { 225dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org if (!selected_window_) 226dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org return false; 227dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org 228dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org unsigned int num_children; 229dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org ::Window* children; 230dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org ::Window parent; 231dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org ::Window root; 232dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org // Find the root window to pass event to. 233dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org int status = XQueryTree( 234dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org display(), selected_window_, &root, &parent, &children, &num_children); 235dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org if (status == 0) { 236dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org LOG(LS_ERROR) << "Failed to query for the root window."; 237dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org return false; 238dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org } 239dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org 240dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org if (children) 241dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org XFree(children); 242dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org 243dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org XRaiseWindow(display(), selected_window_); 244dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org 245dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org // Some window managers (e.g., metacity in GNOME) consider it illegal to 246dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org // raise a window without also giving it input focus with 247dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org // _NET_ACTIVE_WINDOW, so XRaiseWindow() on its own isn't enough. 248dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org Atom atom = XInternAtom(display(), "_NET_ACTIVE_WINDOW", True); 249dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org if (atom != None) { 250dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org XEvent xev; 251dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org xev.xclient.type = ClientMessage; 252dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org xev.xclient.serial = 0; 253dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org xev.xclient.send_event = True; 254dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org xev.xclient.window = selected_window_; 255dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org xev.xclient.message_type = atom; 256dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org 257dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org // The format member is set to 8, 16, or 32 and specifies whether the 258dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org // data should be viewed as a list of bytes, shorts, or longs. 259dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org xev.xclient.format = 32; 260dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org 261dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org memset(xev.xclient.data.l, 0, sizeof(xev.xclient.data.l)); 262dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org 263dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org XSendEvent(display(), 264dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org root, 265dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org False, 266dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org SubstructureRedirectMask | SubstructureNotifyMask, 267dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org &xev); 268dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org } 269dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org XFlush(display()); 270dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org return true; 271dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org} 272dd6cf04628fd4772e543b5008b5328f6c7988f5ajiayl@webrtc.org 273e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.orgvoid WindowCapturerLinux::Start(Callback* callback) { 274e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org assert(!callback_); 275e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org assert(callback); 276e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 277e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org callback_ = callback; 278e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org} 279e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 280e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.orgvoid WindowCapturerLinux::Capture(const DesktopRegion& region) { 281dcbf62b4cf1d7a28fb002efdf671f784378c8c98jiayl@webrtc.org if (!x_server_pixel_buffer_.IsWindowValid()) { 282dcbf62b4cf1d7a28fb002efdf671f784378c8c98jiayl@webrtc.org LOG(LS_INFO) << "The window is no longer valid."; 283dcbf62b4cf1d7a28fb002efdf671f784378c8c98jiayl@webrtc.org callback_->OnCaptureCompleted(NULL); 284dcbf62b4cf1d7a28fb002efdf671f784378c8c98jiayl@webrtc.org return; 285dcbf62b4cf1d7a28fb002efdf671f784378c8c98jiayl@webrtc.org } 286dcbf62b4cf1d7a28fb002efdf671f784378c8c98jiayl@webrtc.org 287ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org x_display_->ProcessPendingXEvents(); 288ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org 289e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (!has_composite_extension_) { 290e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // Without the Xcomposite extension we capture when the whole window is 291e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // visible on screen and not covered by any other window. This is not 292e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // something we want so instead, just bail out. 293e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org LOG(LS_INFO) << "No Xcomposite extension detected."; 294e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org callback_->OnCaptureCompleted(NULL); 295e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org return; 296e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 297e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 298e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org DesktopFrame* frame = 299e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org new BasicDesktopFrame(x_server_pixel_buffer_.window_size()); 300e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 301e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org x_server_pixel_buffer_.Synchronize(); 302e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org x_server_pixel_buffer_.CaptureRect(DesktopRect::MakeSize(frame->size()), 303e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org frame); 304e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 3058150ff1d7130289b6a65633c67e68ac92ddf4513sergeyu@chromium.org frame->mutable_updated_region()->SetRect( 3068150ff1d7130289b6a65633c67e68ac92ddf4513sergeyu@chromium.org DesktopRect::MakeSize(frame->size())); 3078150ff1d7130289b6a65633c67e68ac92ddf4513sergeyu@chromium.org 308e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org callback_->OnCaptureCompleted(frame); 309e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org} 310e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 311ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.orgbool WindowCapturerLinux::HandleXEvent(const XEvent& event) { 312ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org if (event.type == ConfigureNotify) { 313ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org XConfigureEvent xce = event.xconfigure; 314ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org if (!DesktopSize(xce.width, xce.height).equals( 315ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org x_server_pixel_buffer_.window_size())) { 316ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org if (!x_server_pixel_buffer_.Init(display(), selected_window_)) { 317ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org LOG(LS_ERROR) << "Failed to initialize pixel buffer after resizing."; 318ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org } 319ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org return true; 320ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org } 321ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org } 322ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org return false; 323ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org} 324ab23a2d259a9754d3f09b96c1482323c7b9f43aejiayl@webrtc.org 325e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org::Window WindowCapturerLinux::GetApplicationWindow(::Window window) { 326e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // Get WM_STATE property of the window. 32791685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org XWindowProperty<uint32_t> window_state(display(), window, wm_state_atom_); 328e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 329e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // WM_STATE is considered to be set to WithdrawnState when it missing. 330e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org int32_t state = window_state.is_valid() ? 331e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org *window_state.data() : WithdrawnState; 332e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 333e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (state == NormalState) { 334e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // Window has WM_STATE==NormalState. Return it. 335e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org return window; 336e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } else if (state == IconicState) { 337e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // Window is in minimized. Skip it. 338e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org return 0; 339e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 340e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 341e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // If the window is in WithdrawnState then look at all of its children. 342e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org ::Window root, parent; 343e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org ::Window *children; 344e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org unsigned int num_children; 34591685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org if (!XQueryTree(display(), window, &root, &parent, &children, 346e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org &num_children)) { 347e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org LOG(LS_ERROR) << "Failed to query for child windows although window" 348e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org << "does not have a valid WM_STATE."; 349e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org return 0; 350e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 351e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org ::Window app_window = 0; 352e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org for (unsigned int i = 0; i < num_children; ++i) { 353e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org app_window = GetApplicationWindow(children[i]); 354e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (app_window) 355e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org break; 356e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 357e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 358e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (children) 359e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org XFree(children); 360e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org return app_window; 361e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org} 362e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 363e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.orgbool WindowCapturerLinux::IsDesktopElement(::Window window) { 364e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (window == 0) 365e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org return false; 366e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 367e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // First look for _NET_WM_WINDOW_TYPE. The standard 368e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // (http://standards.freedesktop.org/wm-spec/latest/ar01s05.html#id2760306) 369e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // says this hint *should* be present on all windows, and we use the existence 370e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // of _NET_WM_WINDOW_TYPE_NORMAL in the property to indicate a window is not 371e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // a desktop element (that is, only "normal" windows should be shareable). 37291685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org XWindowProperty<uint32_t> window_type(display(), window, window_type_atom_); 373e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (window_type.is_valid() && window_type.size() > 0) { 374e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org uint32_t* end = window_type.data() + window_type.size(); 375e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org bool is_normal = (end != std::find( 376e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org window_type.data(), end, normal_window_type_atom_)); 377e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org return !is_normal; 378e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 379e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 380e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // Fall back on using the hint. 381e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org XClassHint class_hint; 38291685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org Status status = XGetClassHint(display(), window, &class_hint); 383e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org bool result = false; 384e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (status == 0) { 385e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org // No hints, assume this is a normal application window. 386e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org return result; 387e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 388e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 389e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (strcmp("gnome-panel", class_hint.res_name) == 0 || 390e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org strcmp("desktop_window", class_hint.res_name) == 0) { 391e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org result = true; 392e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 393e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org XFree(class_hint.res_name); 394e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org XFree(class_hint.res_class); 395e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org return result; 396e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org} 397e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 398e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.orgbool WindowCapturerLinux::GetWindowTitle(::Window window, std::string* title) { 399e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org int status; 400e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org bool result = false; 401e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org XTextProperty window_name; 402e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org window_name.value = NULL; 403e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (window) { 40491685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org status = XGetWMName(display(), window, &window_name); 405e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (status && window_name.value && window_name.nitems) { 406e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org int cnt; 407e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org char **list = NULL; 40891685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org status = Xutf8TextPropertyToTextList(display(), &window_name, &list, 409e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org &cnt); 410e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (status >= Success && cnt && *list) { 411e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (cnt > 1) { 412e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org LOG(LS_INFO) << "Window has " << cnt 413e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org << " text properties, only using the first one."; 414e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 415e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org *title = *list; 416e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org result = true; 417e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 418e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (list) 419e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org XFreeStringList(list); 420e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 421e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org if (window_name.value) 422e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org XFree(window_name.value); 423e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org } 424e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org return result; 425e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org} 426e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 427e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org} // namespace 428e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 429e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org// static 43091685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.orgWindowCapturer* WindowCapturer::Create(const DesktopCaptureOptions& options) { 43191685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org if (!options.x_display()) 43291685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org return NULL; 43391685dc421db7dcdc24f6a154de9b92eababf6fdsergeyu@chromium.org return new WindowCapturerLinux(options); 434e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org} 435e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org 436e562e02f31a3d39f06d6cdab11a28104c60bccd8sergeyu@chromium.org} // namespace webrtc 437