13d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org/*
23d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
33d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org *
43d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org *  Use of this source code is governed by a BSD-style license
53d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org *  that can be found in the LICENSE file in the root of the source
63d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org *  tree. An additional intellectual property rights grant can be found
73d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org *  in the file PATENTS.  All contributing project authors may
83d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org *  be found in the AUTHORS file in the root of the source tree.
93d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org */
103d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
113d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/modules/desktop_capture/screen_capturer.h"
123d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
133d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include <string.h>
143d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include <set>
153d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
163d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include <X11/extensions/Xdamage.h>
173d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include <X11/extensions/Xfixes.h>
183d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include <X11/Xlib.h>
193d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include <X11/Xutil.h>
203d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
214f847da5a004ae18a5527232d8e982fe0d4cb77dpbos#include "webrtc/base/checks.h"
2200b8f6b3643332cce1ee711715f7fbb824d793cakwiberg@webrtc.org#include "webrtc/base/scoped_ptr.h"
23894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
243d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/modules/desktop_capture/desktop_frame.h"
253d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/modules/desktop_capture/differ.h"
263d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/modules/desktop_capture/screen_capture_frame_queue.h"
273d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/modules/desktop_capture/screen_capturer_helper.h"
283d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org#include "webrtc/modules/desktop_capture/x11/x_server_pixel_buffer.h"
2998f53510b222f71fdd8b799b2f33737ceeb28c61Henrik Kjellander#include "webrtc/system_wrappers/include/logging.h"
3098f53510b222f71fdd8b799b2f33737ceeb28c61Henrik Kjellander#include "webrtc/system_wrappers/include/tick_util.h"
313d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
323d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgnamespace webrtc {
333d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgnamespace {
343d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
353d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org// A class to perform video frame capturing for Linux.
367419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.orgclass ScreenCapturerLinux : public ScreenCapturer,
377419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org                            public SharedXDisplay::XEventHandler {
383d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org public:
393d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  ScreenCapturerLinux();
403d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  virtual ~ScreenCapturerLinux();
413d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
423d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // TODO(ajwong): Do we really want this to be synchronous?
43894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org  bool Init(const DesktopCaptureOptions& options);
443d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
453d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // DesktopCapturer interface.
4614665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org  void Start(Callback* delegate) override;
4714665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org  void Capture(const DesktopRegion& region) override;
483d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
493d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // ScreenCapturer interface.
5014665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org  bool GetScreenList(ScreenList* screens) override;
5114665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org  bool SelectScreen(ScreenId id) override;
523d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
533d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org private:
54894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org  Display* display() { return options_.x_display()->display(); }
55894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org
567419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org  // SharedXDisplay::XEventHandler interface.
5714665ff7d4024d07e58622f498b23fd980001871kjellander@webrtc.org  bool HandleXEvent(const XEvent& event) override;
583d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
597419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org  void InitXDamage();
603d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
613d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // Capture screen pixels to the current buffer in the queue. In the DAMAGE
623d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // case, the ScreenCapturerHelper already holds the list of invalid rectangles
637419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org  // from HandleXEvent(). In the non-DAMAGE case, this captures the
643d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // whole screen, then calculates some invalid rectangles that include any
653d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // differences between this and the previous capture.
663d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  DesktopFrame* CaptureScreen();
673d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
689f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  // Called when the screen configuration is changed.
699f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  void ScreenConfigurationChanged();
703d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
713d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // Synchronize the current buffer with |last_buffer_|, by copying pixels from
723d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // the area of |last_invalid_rects|.
733d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // Note this only works on the assumption that kNumBuffers == 2, as
743d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // |last_invalid_rects| holds the differences from the previous buffer and
753d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // the one prior to that (which will then be the current buffer).
763d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  void SynchronizeFrame();
773d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
783d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  void DeinitXlib();
793d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
80894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org  DesktopCaptureOptions options_;
81894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org
823d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  Callback* callback_;
833d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
843d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // X11 graphics context.
853d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  GC gc_;
863d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  Window root_window_;
873d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
883d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // XFixes.
893d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  bool has_xfixes_;
903d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  int xfixes_event_base_;
913d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  int xfixes_error_base_;
923d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
933d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // XDamage information.
943d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  bool use_damage_;
953d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  Damage damage_handle_;
963d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  int damage_event_base_;
973d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  int damage_error_base_;
983d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  XserverRegion damage_region_;
993d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1003d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // Access to the X Server's pixel buffer.
1013d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  XServerPixelBuffer x_server_pixel_buffer_;
1023d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1033d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // A thread-safe list of invalid rectangles, and the size of the most
1043d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // recently captured screen.
1053d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  ScreenCapturerHelper helper_;
1063d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1073d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // Queue of the frames buffers.
1083d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  ScreenCaptureFrameQueue queue_;
1093d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1103d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // Invalid region from the previous capture. This is used to synchronize the
1113d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // current with the last buffer used.
1123d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  DesktopRegion last_invalid_region_;
1133d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1143d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // |Differ| for use when polling for changes.
11500b8f6b3643332cce1ee711715f7fbb824d793cakwiberg@webrtc.org  rtc::scoped_ptr<Differ> differ_;
1163d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1173c089d751ede283e21e186885eaf705c3257ccd2henrikg  RTC_DISALLOW_COPY_AND_ASSIGN(ScreenCapturerLinux);
1183d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org};
1193d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1203d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgScreenCapturerLinux::ScreenCapturerLinux()
1213d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    : callback_(NULL),
1223d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      gc_(NULL),
1233d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      root_window_(BadValue),
1243d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      has_xfixes_(false),
1253d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      xfixes_event_base_(-1),
1263d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      xfixes_error_base_(-1),
1273d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      use_damage_(false),
1283d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      damage_handle_(0),
1293d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      damage_event_base_(-1),
1303d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      damage_error_base_(-1),
1313d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      damage_region_(0) {
1323d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  helper_.SetLogGridSize(4);
1333d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}
1343d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1353d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgScreenCapturerLinux::~ScreenCapturerLinux() {
1367419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org  options_.x_display()->RemoveEventHandler(ConfigureNotify, this);
1377419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org  if (use_damage_) {
1387419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org    options_.x_display()->RemoveEventHandler(
1397419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org        damage_event_base_ + XDamageNotify, this);
1407419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org  }
1413d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  DeinitXlib();
1423d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}
1433d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
144894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.orgbool ScreenCapturerLinux::Init(const DesktopCaptureOptions& options) {
145894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org  options_ = options;
1463d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
147894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org  root_window_ = RootWindow(display(), DefaultScreen(display()));
1483d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  if (root_window_ == BadValue) {
1493d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    LOG(LS_ERROR) << "Unable to get the root window";
1503d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    DeinitXlib();
1513d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    return false;
1523d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
1533d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
154894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org  gc_ = XCreateGC(display(), root_window_, 0, NULL);
1553d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  if (gc_ == NULL) {
1563d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    LOG(LS_ERROR) << "Unable to get graphics context";
1573d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    DeinitXlib();
1583d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    return false;
1593d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
1603d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1617419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org  options_.x_display()->AddEventHandler(ConfigureNotify, this);
1627419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org
1633d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // Check for XFixes extension. This is required for cursor shape
1643d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // notifications, and for our use of XDamage.
165894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org  if (XFixesQueryExtension(display(), &xfixes_event_base_,
1663d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org                           &xfixes_error_base_)) {
1673d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    has_xfixes_ = true;
1683d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  } else {
1693d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    LOG(LS_INFO) << "X server does not support XFixes.";
1703d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
1713d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1723d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // Register for changes to the dimensions of the root window.
173894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org  XSelectInput(display(), root_window_, StructureNotifyMask);
1743d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
175894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org  if (!x_server_pixel_buffer_.Init(display(), DefaultRootWindow(display()))) {
1769f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    LOG(LS_ERROR) << "Failed to initialize pixel buffer.";
1779f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    return false;
1789f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  }
1793d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
180894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org  if (options_.use_update_notifications()) {
1813d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    InitXDamage();
1823d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
1833d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1843d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  return true;
1853d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}
1863d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1873d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgvoid ScreenCapturerLinux::InitXDamage() {
1883d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // Our use of XDamage requires XFixes.
1893d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  if (!has_xfixes_) {
1903d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    return;
1913d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
1923d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
1933d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // Check for XDamage extension.
194894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org  if (!XDamageQueryExtension(display(), &damage_event_base_,
1953d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org                             &damage_error_base_)) {
1963d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    LOG(LS_INFO) << "X server does not support XDamage.";
1973d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    return;
1983d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
1993d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
2003d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // TODO(lambroslambrou): Disable DAMAGE in situations where it is known
2013d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // to fail, such as when Desktop Effects are enabled, with graphics
2023d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // drivers (nVidia, ATI) that fail to report DAMAGE notifications
2033d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // properly.
2043d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
2053d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // Request notifications every time the screen becomes damaged.
206894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org  damage_handle_ = XDamageCreate(display(), root_window_,
2073d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org                                 XDamageReportNonEmpty);
2083d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  if (!damage_handle_) {
2093d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    LOG(LS_ERROR) << "Unable to initialize XDamage.";
2103d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    return;
2113d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
2123d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
2133d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // Create an XFixes server-side region to collate damage into.
214894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org  damage_region_ = XFixesCreateRegion(display(), 0, 0);
2153d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  if (!damage_region_) {
216894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org    XDamageDestroy(display(), damage_handle_);
2173d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    LOG(LS_ERROR) << "Unable to create XFixes region.";
2183d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    return;
2193d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
2203d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
2217419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org  options_.x_display()->AddEventHandler(
2227419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org      damage_event_base_ + XDamageNotify, this);
2237419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org
2243d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  use_damage_ = true;
2253d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  LOG(LS_INFO) << "Using XDamage extension.";
2263d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}
2273d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
2283d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgvoid ScreenCapturerLinux::Start(Callback* callback) {
22991d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg  RTC_DCHECK(!callback_);
23091d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg  RTC_DCHECK(callback);
2313d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
2323d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  callback_ = callback;
2333d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}
2343d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
2353d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgvoid ScreenCapturerLinux::Capture(const DesktopRegion& region) {
2363d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  TickTime capture_start_time = TickTime::Now();
2373d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
2383d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  queue_.MoveToNextFrame();
2393d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
2403d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // Process XEvents for XDamage and cursor shape tracking.
2417419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org  options_.x_display()->ProcessPendingXEvents();
2423d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
2439f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  // ProcessPendingXEvents() may call ScreenConfigurationChanged() which
2449f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  // reinitializes |x_server_pixel_buffer_|. Check if the pixel buffer is still
2459f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  // in a good shape.
2469f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  if (!x_server_pixel_buffer_.is_initialized()) {
2479f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org     // We failed to initialize pixel buffer.
2489f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org     callback_->OnCaptureCompleted(NULL);
2499f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org     return;
2509f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  }
2519f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org
2523d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // If the current frame is from an older generation then allocate a new one.
2533d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // Note that we can't reallocate other buffers at this point, since the caller
2543d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // may still be reading from them.
2553d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  if (!queue_.current_frame()) {
25600b8f6b3643332cce1ee711715f7fbb824d793cakwiberg@webrtc.org    rtc::scoped_ptr<DesktopFrame> frame(
2579f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org        new BasicDesktopFrame(x_server_pixel_buffer_.window_size()));
2583d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    queue_.ReplaceCurrentFrame(frame.release());
2593d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
2603d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
2613d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // Refresh the Differ helper used by CaptureFrame(), if needed.
2623d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  DesktopFrame* frame = queue_.current_frame();
2633d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  if (!use_damage_ && (
2643d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      !differ_.get() ||
2653d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      (differ_->width() != frame->size().width()) ||
2663d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      (differ_->height() != frame->size().height()) ||
2673d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      (differ_->bytes_per_row() != frame->stride()))) {
2683d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    differ_.reset(new Differ(frame->size().width(), frame->size().height(),
2693d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org                             DesktopFrame::kBytesPerPixel,
2703d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org                             frame->stride()));
2713d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
2723d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
2733d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  DesktopFrame* result = CaptureScreen();
2743d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  last_invalid_region_ = result->updated_region();
2753d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  result->set_capture_time_ms(
2763d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      (TickTime::Now() - capture_start_time).Milliseconds());
2773d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  callback_->OnCaptureCompleted(result);
2783d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}
2793d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
280017b6190106cb8309b70ef9d04e0655f6ed9e656jiayl@webrtc.orgbool ScreenCapturerLinux::GetScreenList(ScreenList* screens) {
28191d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg  RTC_DCHECK(screens->size() == 0);
282017b6190106cb8309b70ef9d04e0655f6ed9e656jiayl@webrtc.org  // TODO(jiayl): implement screen enumeration.
283017b6190106cb8309b70ef9d04e0655f6ed9e656jiayl@webrtc.org  Screen default_screen;
284017b6190106cb8309b70ef9d04e0655f6ed9e656jiayl@webrtc.org  default_screen.id = 0;
285017b6190106cb8309b70ef9d04e0655f6ed9e656jiayl@webrtc.org  screens->push_back(default_screen);
286017b6190106cb8309b70ef9d04e0655f6ed9e656jiayl@webrtc.org  return true;
287017b6190106cb8309b70ef9d04e0655f6ed9e656jiayl@webrtc.org}
288017b6190106cb8309b70ef9d04e0655f6ed9e656jiayl@webrtc.org
289017b6190106cb8309b70ef9d04e0655f6ed9e656jiayl@webrtc.orgbool ScreenCapturerLinux::SelectScreen(ScreenId id) {
290017b6190106cb8309b70ef9d04e0655f6ed9e656jiayl@webrtc.org  // TODO(jiayl): implement screen selection.
291017b6190106cb8309b70ef9d04e0655f6ed9e656jiayl@webrtc.org  return true;
292017b6190106cb8309b70ef9d04e0655f6ed9e656jiayl@webrtc.org}
293017b6190106cb8309b70ef9d04e0655f6ed9e656jiayl@webrtc.org
2947419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.orgbool ScreenCapturerLinux::HandleXEvent(const XEvent& event) {
2957419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org  if (use_damage_ && (event.type == damage_event_base_ + XDamageNotify)) {
2967419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org    const XDamageNotifyEvent* damage_event =
2977419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org        reinterpret_cast<const XDamageNotifyEvent*>(&event);
2987419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org    if (damage_event->damage != damage_handle_)
2997419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org      return false;
30091d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg    RTC_DCHECK(damage_event->level == XDamageReportNonEmpty);
3017419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org    return true;
3027419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org  } else if (event.type == ConfigureNotify) {
3037419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org    ScreenConfigurationChanged();
3047419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org    return true;
3053d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
3067419a723832e7b74d1fbbd21d95f86a65c0e1da7sergeyu@chromium.org  return false;
3073d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}
3083d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
3093d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgDesktopFrame* ScreenCapturerLinux::CaptureScreen() {
3103d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  DesktopFrame* frame = queue_.current_frame()->Share();
3119f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  assert(x_server_pixel_buffer_.window_size().equals(frame->size()));
3123d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
3133d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // Pass the screen size to the helper, so it can clip the invalid region if it
3143d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // expands that region to a grid.
3153d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  helper_.set_size_most_recent(frame->size());
3163d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
3173d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // In the DAMAGE case, ensure the frame is up-to-date with the previous frame
3183d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // if any.  If there isn't a previous frame, that means a screen-resolution
3193d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // change occurred, and |invalid_rects| will be updated to include the whole
3203d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // screen.
3213d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  if (use_damage_ && queue_.previous_frame())
3223d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    SynchronizeFrame();
3233d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
3243d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  DesktopRegion* updated_region = frame->mutable_updated_region();
3253d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
3263d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  x_server_pixel_buffer_.Synchronize();
3273d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  if (use_damage_ && queue_.previous_frame()) {
3283d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    // Atomically fetch and clear the damage region.
329894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org    XDamageSubtract(display(), damage_handle_, None, damage_region_);
3303d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    int rects_num = 0;
3313d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    XRectangle bounds;
332894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org    XRectangle* rects = XFixesFetchRegionAndBounds(display(), damage_region_,
3333d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org                                                   &rects_num, &bounds);
3343d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    for (int i = 0; i < rects_num; ++i) {
3353d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      updated_region->AddRect(DesktopRect::MakeXYWH(
3363d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org          rects[i].x, rects[i].y, rects[i].width, rects[i].height));
3373d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    }
3383d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    XFree(rects);
3393d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    helper_.InvalidateRegion(*updated_region);
3403d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
3413d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    // Capture the damaged portions of the desktop.
3423d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    helper_.TakeInvalidRegion(updated_region);
3433d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
3443d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    // Clip the damaged portions to the current screen size, just in case some
3453d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    // spurious XDamage notifications were received for a previous (larger)
3463d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    // screen size.
3473d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    updated_region->IntersectWith(
3489f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org        DesktopRect::MakeSize(x_server_pixel_buffer_.window_size()));
3493d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
3503d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    for (DesktopRegion::Iterator it(*updated_region);
3513d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org         !it.IsAtEnd(); it.Advance()) {
3529f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org      x_server_pixel_buffer_.CaptureRect(it.rect(), frame);
3533d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    }
3543d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  } else {
3553d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    // Doing full-screen polling, or this is the first capture after a
3563d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    // screen-resolution change.  In either case, need a full-screen capture.
3579f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    DesktopRect screen_rect = DesktopRect::MakeSize(frame->size());
3589f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    x_server_pixel_buffer_.CaptureRect(screen_rect, frame);
3593d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
3603d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    if (queue_.previous_frame()) {
3613d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      // Full-screen polling, so calculate the invalid rects here, based on the
3623d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      // changed pixels between current and previous buffers.
36391d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg      RTC_DCHECK(differ_.get() != NULL);
36491d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg      RTC_DCHECK(queue_.previous_frame()->data());
3653d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      differ_->CalcDirtyRegion(queue_.previous_frame()->data(),
3663d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org                               frame->data(), updated_region);
3673d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    } else {
3683d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      // No previous buffer, so always invalidate the whole screen, whether
3693d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      // or not DAMAGE is being used.  DAMAGE doesn't necessarily send a
3703d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      // full-screen notification after a screen-resolution change, so
3713d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      // this is done here.
3723d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org      updated_region->SetRect(screen_rect);
3733d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    }
3743d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
3753d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
3763d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  return frame;
3773d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}
3783d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
3799f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.orgvoid ScreenCapturerLinux::ScreenConfigurationChanged() {
3803d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // Make sure the frame buffers will be reallocated.
3813d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  queue_.Reset();
3823d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
3833d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  helper_.ClearInvalidRegion();
384894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org  if (!x_server_pixel_buffer_.Init(display(), DefaultRootWindow(display()))) {
3859f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org    LOG(LS_ERROR) << "Failed to initialize pixel buffer after screen "
3869f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org        "configuration change.";
3879f282403f258162ca53eb2f16b8e9a26e7970096sergeyu@chromium.org  }
3883d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}
3893d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
3903d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgvoid ScreenCapturerLinux::SynchronizeFrame() {
3913d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // Synchronize the current buffer with the previous one since we do not
3923d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // capture the entire desktop. Note that encoder may be reading from the
3933d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // previous buffer at this time so thread access complaints are false
3943d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // positives.
3953d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
3963d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // TODO(hclam): We can reduce the amount of copying here by subtracting
3973d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // |capturer_helper_|s region from |last_invalid_region_|.
3983d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  // http://crbug.com/92354
39991d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg  RTC_DCHECK(queue_.previous_frame());
4003d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
4013d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  DesktopFrame* current = queue_.current_frame();
4023d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  DesktopFrame* last = queue_.previous_frame();
40391d6edef35e7275879c30ce16ecb8b6dc73c6e4ahenrikg  RTC_DCHECK(current != last);
4043d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  for (DesktopRegion::Iterator it(last_invalid_region_);
4053d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org       !it.IsAtEnd(); it.Advance()) {
4065d85819dd21842cc3e6d74676a292cf9d9142f4esergeyu@chromium.org    current->CopyPixelsFrom(*last, it.rect().top_left(), it.rect());
4073d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
4083d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}
4093d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
4103d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.orgvoid ScreenCapturerLinux::DeinitXlib() {
4113d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  if (gc_) {
412894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org    XFreeGC(display(), gc_);
4133d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    gc_ = NULL;
4143d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
4153d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
4163d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  x_server_pixel_buffer_.Release();
4173d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
418894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org  if (display()) {
419894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org    if (damage_handle_) {
420894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org      XDamageDestroy(display(), damage_handle_);
421894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org      damage_handle_ = 0;
422894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org    }
423894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org
424894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org    if (damage_region_) {
425894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org      XFixesDestroyRegion(display(), damage_region_);
426894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org      damage_region_ = 0;
427894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org    }
4283d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  }
4293d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}
4303d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
4313d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}  // namespace
4323d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
4333d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org// static
434894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.orgScreenCapturer* ScreenCapturer::Create(const DesktopCaptureOptions& options) {
435894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org  if (!options.x_display())
436894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org    return NULL;
4373d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
43800b8f6b3643332cce1ee711715f7fbb824d793cakwiberg@webrtc.org  rtc::scoped_ptr<ScreenCapturerLinux> capturer(new ScreenCapturerLinux());
439894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.org  if (!capturer->Init(options))
4403d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org    capturer.reset();
4413d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org  return capturer.release();
4423d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}
4433d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org
4443d34f66292ad4d3950d94026d08c3659880d30e2sergeyu@chromium.org}  // namespace webrtc
445