LCOV - code coverage report
Current view: top level - media/webrtc/trunk/webrtc/modules/desktop_capture - mouse_cursor_monitor_x11.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 0 103 0.0 %
Date: 2017-07-14 16:53:18 Functions: 0 12 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*
       2             :  *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
       3             :  *
       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
       6             :  *  tree. An additional intellectual property rights grant can be found
       7             :  *  in the file PATENTS.  All contributing project authors may
       8             :  *  be found in the AUTHORS file in the root of the source tree.
       9             :  */
      10             : 
      11             : #include <memory>
      12             : 
      13             : #include "webrtc/modules/desktop_capture/mouse_cursor_monitor.h"
      14             : 
      15             : #include <X11/extensions/Xfixes.h>
      16             : #include <X11/Xlib.h>
      17             : #include <X11/Xutil.h>
      18             : 
      19             : #include "webrtc/modules/desktop_capture/desktop_capture_options.h"
      20             : #include "webrtc/modules/desktop_capture/desktop_frame.h"
      21             : #include "webrtc/modules/desktop_capture/mouse_cursor.h"
      22             : #include "webrtc/modules/desktop_capture/x11/x_error_trap.h"
      23             : #include "webrtc/system_wrappers/include/logging.h"
      24             : 
      25             : namespace {
      26             : 
      27             : // WindowCapturer returns window IDs of X11 windows with WM_STATE attribute.
      28             : // These windows may not be immediate children of the root window, because
      29             : // window managers may re-parent them to add decorations. However,
      30             : // XQueryPointer() expects to be passed children of the root. This function
      31             : // searches up the list of the windows to find the root child that corresponds
      32             : // to |window|.
      33           0 : Window GetTopLevelWindow(Display* display, Window window) {
      34           0 :   webrtc::XErrorTrap error_trap(display);
      35             :   while (true) {
      36             :     // If the window is in WithdrawnState then look at all of its children.
      37             :     ::Window root, parent;
      38             :     ::Window *children;
      39             :     unsigned int num_children;
      40           0 :     if (!XQueryTree(display, window, &root, &parent, &children,
      41             :                     &num_children)) {
      42           0 :       LOG(LS_ERROR) << "Failed to query for child windows although window"
      43           0 :                     << "does not have a valid WM_STATE.";
      44           0 :       return None;
      45             :     }
      46           0 :     if (children)
      47           0 :       XFree(children);
      48             : 
      49           0 :     if (parent == root)
      50           0 :       break;
      51             : 
      52           0 :     window = parent;
      53           0 :   }
      54             : 
      55           0 :   return window;
      56             : }
      57             : 
      58             : }  // namespace
      59             : 
      60             : namespace webrtc {
      61             : 
      62             : class MouseCursorMonitorX11 : public MouseCursorMonitor,
      63             :                               public SharedXDisplay::XEventHandler {
      64             :  public:
      65             :   MouseCursorMonitorX11(const DesktopCaptureOptions& options, Window window, Window inner_window);
      66             :   ~MouseCursorMonitorX11() override;
      67             : 
      68             :   void Start(Callback* callback, Mode mode) override;
      69             :   void Stop() override;
      70             :   void Capture() override;
      71             : 
      72             :  private:
      73             :   // SharedXDisplay::XEventHandler interface.
      74             :   bool HandleXEvent(const XEvent& event) override;
      75             : 
      76           0 :   Display* display() { return x_display_->display(); }
      77             : 
      78             :   // Captures current cursor shape and stores it in |cursor_shape_|.
      79             :   void CaptureCursor();
      80             : 
      81             :   rtc::scoped_refptr<SharedXDisplay> x_display_;
      82             :   Callback* callback_;
      83             :   Mode mode_;
      84             :   Window window_;
      85             :   Window inner_window_;
      86             : 
      87             :   bool have_xfixes_;
      88             :   int xfixes_event_base_;
      89             :   int xfixes_error_base_;
      90             : 
      91             :   std::unique_ptr<MouseCursor> cursor_shape_;
      92             : };
      93             : 
      94           0 : MouseCursorMonitorX11::MouseCursorMonitorX11(
      95             :     const DesktopCaptureOptions& options,
      96           0 :     Window window, Window inner_window)
      97             :     : x_display_(options.x_display()),
      98             :       callback_(NULL),
      99             :       mode_(SHAPE_AND_POSITION),
     100             :       window_(window),
     101             :       inner_window_(inner_window),
     102             :       have_xfixes_(false),
     103             :       xfixes_event_base_(-1),
     104           0 :       xfixes_error_base_(-1) {
     105             :   // Set a default initial cursor shape in case XFixes is not present.
     106           0 :   const int kSize = 5;
     107             :   std::unique_ptr<DesktopFrame> default_cursor(
     108           0 :       new BasicDesktopFrame(DesktopSize(kSize, kSize)));
     109             :   const uint8_t pixels[kSize * kSize] = {
     110             :     0x00, 0x00, 0x00, 0x00, 0x00,
     111             :     0x00, 0xff, 0xff, 0xff, 0x00,
     112             :     0x00, 0xff, 0xff, 0xff, 0x00,
     113             :     0x00, 0xff, 0xff, 0xff, 0x00,
     114             :     0x00, 0x00, 0x00, 0x00, 0x00
     115           0 :   };
     116           0 :   uint8_t* ptr = default_cursor->data();
     117           0 :   for (int y = 0; y < kSize; ++y) {
     118           0 :     for (int x = 0; x < kSize; ++x) {
     119           0 :       *ptr++ = pixels[kSize * y + x];
     120           0 :       *ptr++ = pixels[kSize * y + x];
     121           0 :       *ptr++ = pixels[kSize * y + x];
     122           0 :       *ptr++ = 0xff;
     123             :     }
     124             :   }
     125           0 :   DesktopVector hotspot(2, 2);
     126           0 :   cursor_shape_.reset(new MouseCursor(default_cursor.release(), hotspot));
     127           0 : }
     128             : 
     129           0 : MouseCursorMonitorX11::~MouseCursorMonitorX11() {
     130           0 :   Stop();
     131           0 : }
     132             : 
     133           0 : void MouseCursorMonitorX11::Start(Callback* callback, Mode mode) {
     134             :   // Start can be called only if not started
     135           0 :   RTC_DCHECK(!callback_);
     136           0 :   RTC_DCHECK(callback);
     137             : 
     138           0 :   callback_ = callback;
     139           0 :   mode_ = mode;
     140             : 
     141           0 :   have_xfixes_ =
     142           0 :       XFixesQueryExtension(display(), &xfixes_event_base_, &xfixes_error_base_);
     143             : 
     144           0 :   if (have_xfixes_) {
     145             :     // Register for changes to the cursor shape.
     146           0 :     XErrorTrap error_trap(display());
     147           0 :     XFixesSelectCursorInput(display(), window_, XFixesDisplayCursorNotifyMask);
     148           0 :     x_display_->AddEventHandler(xfixes_event_base_ + XFixesCursorNotify, this);
     149             : 
     150           0 :     CaptureCursor();
     151             :   } else {
     152           0 :     LOG(LS_INFO) << "X server does not support XFixes.";
     153             :   }
     154           0 : }
     155             : 
     156           0 : void MouseCursorMonitorX11::Stop() {
     157           0 :   callback_ = NULL;
     158           0 :   if (have_xfixes_) {
     159           0 :     x_display_->RemoveEventHandler(xfixes_event_base_ + XFixesCursorNotify,
     160           0 :                                    this);
     161             :   }
     162           0 : }
     163             : 
     164           0 : void MouseCursorMonitorX11::Capture() {
     165           0 :   RTC_DCHECK(callback_);
     166             : 
     167             :   // Process X11 events in case XFixes has sent cursor notification.
     168           0 :   x_display_->ProcessPendingXEvents();
     169             : 
     170             :   // cursor_shape_| is set only if we were notified of a cursor shape change.
     171           0 :   if (cursor_shape_.get())
     172           0 :     callback_->OnMouseCursor(cursor_shape_.release());
     173             : 
     174             :   // Get cursor position if necessary.
     175           0 :   if (mode_ == SHAPE_AND_POSITION) {
     176             :     int root_x;
     177             :     int root_y;
     178             :     int win_x;
     179             :     int win_y;
     180             :     Window root_window;
     181             :     Window child_window;
     182             :     unsigned int mask;
     183             : 
     184           0 :     XErrorTrap error_trap(display());
     185           0 :     Bool result = XQueryPointer(display(), inner_window_, &root_window, &child_window,
     186           0 :                                 &root_x, &root_y, &win_x, &win_y, &mask);
     187             :     CursorState state;
     188           0 :     if (!result || error_trap.GetLastErrorAndDisable() != 0) {
     189           0 :       state = OUTSIDE;
     190             :     } else {
     191             :       // In screen mode (window_ == root_window) the mouse is always inside.
     192             :       // XQueryPointer() sets |child_window| to None if the cursor is outside
     193             :       // |window_|.
     194           0 :       state =
     195           0 :           (window_ == root_window || child_window != None) ? INSIDE : OUTSIDE;
     196             :     }
     197             : 
     198           0 :     callback_->OnMouseCursorPosition(state,
     199           0 :                                      webrtc::DesktopVector(win_x, win_y));
     200             :   }
     201           0 : }
     202             : 
     203           0 : bool MouseCursorMonitorX11::HandleXEvent(const XEvent& event) {
     204           0 :   if (have_xfixes_ && event.type == xfixes_event_base_ + XFixesCursorNotify) {
     205             :     const XFixesCursorNotifyEvent* cursor_event =
     206           0 :         reinterpret_cast<const XFixesCursorNotifyEvent*>(&event);
     207           0 :     if (cursor_event->subtype == XFixesDisplayCursorNotify) {
     208           0 :       CaptureCursor();
     209             :     }
     210             :     // Return false, even if the event has been handled, because there might be
     211             :     // other listeners for cursor notifications.
     212             :   }
     213           0 :   return false;
     214             : }
     215             : 
     216           0 : void MouseCursorMonitorX11::CaptureCursor() {
     217           0 :   RTC_DCHECK(have_xfixes_);
     218             : 
     219             :   XFixesCursorImage* img;
     220             :   {
     221           0 :     XErrorTrap error_trap(display());
     222           0 :     img = XFixesGetCursorImage(display());
     223           0 :     if (!img || error_trap.GetLastErrorAndDisable() != 0)
     224           0 :        return;
     225             :    }
     226             : 
     227             :    std::unique_ptr<DesktopFrame> image(
     228           0 :        new BasicDesktopFrame(DesktopSize(img->width, img->height)));
     229             : 
     230             :   // Xlib stores 32-bit data in longs, even if longs are 64-bits long.
     231           0 :   unsigned long* src = img->pixels;
     232           0 :   uint32_t* dst = reinterpret_cast<uint32_t*>(image->data());
     233           0 :   uint32_t* dst_end = dst + (img->width * img->height);
     234           0 :   while (dst < dst_end) {
     235           0 :     *dst++ = static_cast<uint32_t>(*src++);
     236             :   }
     237             : 
     238           0 :   DesktopVector hotspot(std::min(img->width, img->xhot),
     239           0 :                         std::min(img->height, img->yhot));
     240             : 
     241           0 :   XFree(img);
     242             : 
     243           0 :   cursor_shape_.reset(new MouseCursor(image.release(), hotspot));
     244             : }
     245             : 
     246             : // static
     247           0 : MouseCursorMonitor* MouseCursorMonitor::CreateForWindow(
     248             :     const DesktopCaptureOptions& options, WindowId window) {
     249           0 :   if (!options.x_display())
     250           0 :     return NULL;
     251           0 :   WindowId outer_window = GetTopLevelWindow(options.x_display()->display(), window);
     252           0 :   if (outer_window == None)
     253           0 :     return NULL;
     254           0 :   return new MouseCursorMonitorX11(options, outer_window, window);
     255             : }
     256             : 
     257           0 : MouseCursorMonitor* MouseCursorMonitor::CreateForScreen(
     258             :     const DesktopCaptureOptions& options,
     259             :     ScreenId screen) {
     260           0 :   if (!options.x_display())
     261           0 :     return NULL;
     262           0 :   WindowId window = DefaultRootWindow(options.x_display()->display());
     263           0 :   return new MouseCursorMonitorX11(options, window, window);
     264             : }
     265             : 
     266             : }  // namespace webrtc

Generated by: LCOV version 1.13