1af54d4b3a12f79ebcfe10695a8ec2b1da80ab1f4sergeyu@chromium.org/* 2af54d4b3a12f79ebcfe10695a8ec2b1da80ab1f4sergeyu@chromium.org * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3af54d4b3a12f79ebcfe10695a8ec2b1da80ab1f4sergeyu@chromium.org * 4af54d4b3a12f79ebcfe10695a8ec2b1da80ab1f4sergeyu@chromium.org * Use of this source code is governed by a BSD-style license 5af54d4b3a12f79ebcfe10695a8ec2b1da80ab1f4sergeyu@chromium.org * that can be found in the LICENSE file in the root of the source 6af54d4b3a12f79ebcfe10695a8ec2b1da80ab1f4sergeyu@chromium.org * tree. An additional intellectual property rights grant can be found 7af54d4b3a12f79ebcfe10695a8ec2b1da80ab1f4sergeyu@chromium.org * in the file PATENTS. All contributing project authors may 8af54d4b3a12f79ebcfe10695a8ec2b1da80ab1f4sergeyu@chromium.org * be found in the AUTHORS file in the root of the source tree. 9af54d4b3a12f79ebcfe10695a8ec2b1da80ab1f4sergeyu@chromium.org */ 10af54d4b3a12f79ebcfe10695a8ec2b1da80ab1f4sergeyu@chromium.org 11af54d4b3a12f79ebcfe10695a8ec2b1da80ab1f4sergeyu@chromium.org#include "webrtc/modules/desktop_capture/mouse_cursor_monitor.h" 12af54d4b3a12f79ebcfe10695a8ec2b1da80ab1f4sergeyu@chromium.org 132873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org#include <assert.h> 142873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org#include <ApplicationServices/ApplicationServices.h> 152873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org#include <Cocoa/Cocoa.h> 162873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org#include <CoreFoundation/CoreFoundation.h> 172873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 18678f1909fc6918687aedd02949bcdf0f0e1ac682jiayl@webrtc.org#include "webrtc/base/macutils.h" 195e9b73011bf23ffbf48d39d6704e65f037a9bdd7jiayl@webrtc.org#include "webrtc/modules/desktop_capture/desktop_capture_options.h" 202873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org#include "webrtc/modules/desktop_capture/desktop_frame.h" 211d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org#include "webrtc/modules/desktop_capture/mac/desktop_configuration.h" 225e9b73011bf23ffbf48d39d6704e65f037a9bdd7jiayl@webrtc.org#include "webrtc/modules/desktop_capture/mac/desktop_configuration_monitor.h" 23678f1909fc6918687aedd02949bcdf0f0e1ac682jiayl@webrtc.org#include "webrtc/modules/desktop_capture/mac/full_screen_chrome_window_detector.h" 242873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org#include "webrtc/modules/desktop_capture/mouse_cursor.h" 251d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org#include "webrtc/system_wrappers/interface/logging.h" 262873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org#include "webrtc/system_wrappers/interface/scoped_ptr.h" 275e9b73011bf23ffbf48d39d6704e65f037a9bdd7jiayl@webrtc.org#include "webrtc/system_wrappers/interface/scoped_refptr.h" 28af54d4b3a12f79ebcfe10695a8ec2b1da80ab1f4sergeyu@chromium.org 29af54d4b3a12f79ebcfe10695a8ec2b1da80ab1f4sergeyu@chromium.orgnamespace webrtc { 30af54d4b3a12f79ebcfe10695a8ec2b1da80ab1f4sergeyu@chromium.org 312873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.orgclass MouseCursorMonitorMac : public MouseCursorMonitor { 322873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org public: 335e9b73011bf23ffbf48d39d6704e65f037a9bdd7jiayl@webrtc.org MouseCursorMonitorMac(const DesktopCaptureOptions& options, 341d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org CGWindowID window_id, 351d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org ScreenId screen_id); 362873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org virtual ~MouseCursorMonitorMac(); 372873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 382873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org virtual void Init(Callback* callback, Mode mode) OVERRIDE; 392873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org virtual void Capture() OVERRIDE; 402873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 412873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org private: 421d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org static void DisplaysReconfiguredCallback(CGDirectDisplayID display, 431d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org CGDisplayChangeSummaryFlags flags, 441d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org void *user_parameter); 451d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org void DisplaysReconfigured(CGDirectDisplayID display, 461d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org CGDisplayChangeSummaryFlags flags); 471d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org 482873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org void CaptureImage(); 492873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 505e9b73011bf23ffbf48d39d6704e65f037a9bdd7jiayl@webrtc.org scoped_refptr<DesktopConfigurationMonitor> configuration_monitor_; 512873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CGWindowID window_id_; 521d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org ScreenId screen_id_; 532873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org Callback* callback_; 542873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org Mode mode_; 552873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org scoped_ptr<MouseCursor> last_cursor_; 56678f1909fc6918687aedd02949bcdf0f0e1ac682jiayl@webrtc.org scoped_refptr<FullScreenChromeWindowDetector> 57678f1909fc6918687aedd02949bcdf0f0e1ac682jiayl@webrtc.org full_screen_chrome_window_detector_; 582873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org}; 592873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 605e9b73011bf23ffbf48d39d6704e65f037a9bdd7jiayl@webrtc.orgMouseCursorMonitorMac::MouseCursorMonitorMac( 615e9b73011bf23ffbf48d39d6704e65f037a9bdd7jiayl@webrtc.org const DesktopCaptureOptions& options, 621d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org CGWindowID window_id, 631d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org ScreenId screen_id) 645e9b73011bf23ffbf48d39d6704e65f037a9bdd7jiayl@webrtc.org : configuration_monitor_(options.configuration_monitor()), 655e9b73011bf23ffbf48d39d6704e65f037a9bdd7jiayl@webrtc.org window_id_(window_id), 661d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org screen_id_(screen_id), 672873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org callback_(NULL), 68678f1909fc6918687aedd02949bcdf0f0e1ac682jiayl@webrtc.org mode_(SHAPE_AND_POSITION), 69678f1909fc6918687aedd02949bcdf0f0e1ac682jiayl@webrtc.org full_screen_chrome_window_detector_( 70678f1909fc6918687aedd02949bcdf0f0e1ac682jiayl@webrtc.org options.full_screen_chrome_window_detector()) { 711d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org assert(window_id == kCGNullWindowID || screen_id == kInvalidScreenId); 72678f1909fc6918687aedd02949bcdf0f0e1ac682jiayl@webrtc.org if (screen_id != kInvalidScreenId && 73678f1909fc6918687aedd02949bcdf0f0e1ac682jiayl@webrtc.org rtc::GetOSVersionName() < rtc::kMacOSLion) { 741d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org // Single screen capture is not supported on pre OS X 10.7. 751d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org screen_id_ = kFullDesktopScreenId; 761d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org } 772873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org} 782873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 792873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.orgMouseCursorMonitorMac::~MouseCursorMonitorMac() {} 802873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 812873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.orgvoid MouseCursorMonitorMac::Init(Callback* callback, Mode mode) { 822873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org assert(!callback_); 832873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org assert(callback); 842873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 852873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org callback_ = callback; 862873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org mode_ = mode; 872873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org} 882873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 892873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.orgvoid MouseCursorMonitorMac::Capture() { 902873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org assert(callback_); 912873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 922873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CaptureImage(); 932873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 942873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org if (mode_ != SHAPE_AND_POSITION) 952873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org return; 962873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 972873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CursorState state = INSIDE; 982873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 992873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CGEventRef event = CGEventCreate(NULL); 1002873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CGPoint gc_position = CGEventGetLocation(event); 1012873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CFRelease(event); 1022873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 1032873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org DesktopVector position(gc_position.x, gc_position.y); 1042873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 1051d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org configuration_monitor_->Lock(); 1061d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org MacDesktopConfiguration configuration = 1071d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org configuration_monitor_->desktop_configuration(); 1081d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org configuration_monitor_->Unlock(); 1091d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org float scale = 1.0f; 1101d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org 1111d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org // Find the dpi to physical pixel scale for the screen where the mouse cursor 1121d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org // is. 1131d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org for (MacDisplayConfigurations::iterator it = configuration.displays.begin(); 1141d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org it != configuration.displays.end(); ++it) { 1151d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org if (it->bounds.Contains(position)) { 1161d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org scale = it->dip_to_pixel_scale; 1171d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org break; 1181d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org } 1191d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org } 1202873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org // If we are capturing cursor for a specific window then we need to figure out 1212873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org // if the current mouse position is covered by another window and also adjust 1222873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org // |position| to make it relative to the window origin. 1232873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org if (window_id_ != kCGNullWindowID) { 124678f1909fc6918687aedd02949bcdf0f0e1ac682jiayl@webrtc.org CGWindowID on_screen_window = window_id_; 125678f1909fc6918687aedd02949bcdf0f0e1ac682jiayl@webrtc.org if (full_screen_chrome_window_detector_) { 126678f1909fc6918687aedd02949bcdf0f0e1ac682jiayl@webrtc.org CGWindowID full_screen_window = 127678f1909fc6918687aedd02949bcdf0f0e1ac682jiayl@webrtc.org full_screen_chrome_window_detector_->FindFullScreenWindow(window_id_); 128678f1909fc6918687aedd02949bcdf0f0e1ac682jiayl@webrtc.org 129678f1909fc6918687aedd02949bcdf0f0e1ac682jiayl@webrtc.org if (full_screen_window != kCGNullWindowID) 130678f1909fc6918687aedd02949bcdf0f0e1ac682jiayl@webrtc.org on_screen_window = full_screen_window; 131678f1909fc6918687aedd02949bcdf0f0e1ac682jiayl@webrtc.org } 132678f1909fc6918687aedd02949bcdf0f0e1ac682jiayl@webrtc.org 133678f1909fc6918687aedd02949bcdf0f0e1ac682jiayl@webrtc.org // Get list of windows that may be covering parts of |on_screen_window|. 1342873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org // CGWindowListCopyWindowInfo() returns windows in order from front to back, 135678f1909fc6918687aedd02949bcdf0f0e1ac682jiayl@webrtc.org // so |on_screen_window| is expected to be the last in the list. 1362873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CFArrayRef window_array = 1372873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly | 1382873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org kCGWindowListOptionOnScreenAboveWindow | 1392873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org kCGWindowListOptionIncludingWindow, 140678f1909fc6918687aedd02949bcdf0f0e1ac682jiayl@webrtc.org on_screen_window); 1412873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org bool found_window = false; 1422873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org if (window_array) { 1432873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CFIndex count = CFArrayGetCount(window_array); 1442873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org for (CFIndex i = 0; i < count; ++i) { 1452873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>( 1462873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CFArrayGetValueAtIndex(window_array, i)); 1472873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 1482873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org // Skip the Dock window. Dock window covers the whole screen, but it is 1492873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org // transparent. 1502873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CFStringRef window_name = reinterpret_cast<CFStringRef>( 1512873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CFDictionaryGetValue(window, kCGWindowName)); 1522873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org if (window_name && CFStringCompare(window_name, CFSTR("Dock"), 0) == 0) 1532873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org continue; 1542873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 1552873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CFDictionaryRef window_bounds = reinterpret_cast<CFDictionaryRef>( 1562873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CFDictionaryGetValue(window, kCGWindowBounds)); 1572873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CFNumberRef window_number = reinterpret_cast<CFNumberRef>( 1582873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CFDictionaryGetValue(window, kCGWindowNumber)); 1592873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 1602873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org if (window_bounds && window_number) { 1612873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CGRect gc_window_rect; 1622873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org if (!CGRectMakeWithDictionaryRepresentation(window_bounds, 1632873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org &gc_window_rect)) { 1642873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org continue; 1652873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org } 1662873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org DesktopRect window_rect = 1672873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org DesktopRect::MakeXYWH(gc_window_rect.origin.x, 1682873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org gc_window_rect.origin.y, 1692873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org gc_window_rect.size.width, 1702873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org gc_window_rect.size.height); 1712873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 1722873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CGWindowID window_id; 1732873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org if (!CFNumberGetValue(window_number, kCFNumberIntType, &window_id)) 1742873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org continue; 1752873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 176678f1909fc6918687aedd02949bcdf0f0e1ac682jiayl@webrtc.org if (window_id == on_screen_window) { 1772873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org found_window = true; 1782873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org if (!window_rect.Contains(position)) 1792873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org state = OUTSIDE; 1802873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org position = position.subtract(window_rect.top_left()); 1812873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 1822873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org assert(i == count - 1); 1832873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org break; 1842873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org } else if (window_rect.Contains(position)) { 1852873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org state = OUTSIDE; 1862873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org position.set(-1, -1); 1872873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org break; 1882873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org } 1892873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org } 1902873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org } 1912873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CFRelease(window_array); 1922873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org } 1932873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org if (!found_window) { 1942873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org // If we failed to get list of windows or the window wasn't in the list 1952873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org // pretend that the cursor is outside the window. This can happen, e.g. if 1962873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org // the window was closed. 1972873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org state = OUTSIDE; 1982873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org position.set(-1, -1); 1992873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org } 2001d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org } else { 2011d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org assert(screen_id_ >= kFullDesktopScreenId); 2021d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org if (screen_id_ != kFullDesktopScreenId) { 2031d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org // For single screen capturing, convert the position to relative to the 2041d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org // target screen. 2051d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org const MacDisplayConfiguration* config = 2061d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org configuration.FindDisplayConfigurationById( 2071d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org static_cast<CGDirectDisplayID>(screen_id_)); 2081d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org if (config) { 2091d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org if (!config->pixel_bounds.Contains(position)) 2101d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org state = OUTSIDE; 2111d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org position = position.subtract(config->bounds.top_left()); 2121d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org } else { 2131d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org // The target screen is no longer valid. 2141d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org state = OUTSIDE; 2151d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org position.set(-1, -1); 2161d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org } 2171d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org } else { 218998d063211cf856d91181e16d6eb303a1a9fd229sergeyu@chromium.org position.subtract(configuration.bounds.top_left()); 2191d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org } 2201d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org } 2211d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org if (state == INSIDE) { 2221d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org // Convert Density Independent Pixel to physical pixel. 2231d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org position = DesktopVector(round(position.x() * scale), 2241d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org round(position.y() * scale)); 2252873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org } 2262873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org callback_->OnMouseCursorPosition(state, position); 2272873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org} 2282873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 2292873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.orgvoid MouseCursorMonitorMac::CaptureImage() { 2302873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org NSCursor* nscursor = [NSCursor currentSystemCursor]; 2312873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 2322873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org NSImage* nsimage = [nscursor image]; 2332873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org NSSize nssize = [nsimage size]; 2342873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org DesktopSize size(nssize.width, nssize.height); 2352873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org NSPoint nshotspot = [nscursor hotSpot]; 2362873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org DesktopVector hotspot( 23759fdf2d7bed0c080fa35677170ec9f02df30c2cbsergeyu@chromium.org std::max(0, std::min(size.width(), static_cast<int>(nshotspot.x))), 23859fdf2d7bed0c080fa35677170ec9f02df30c2cbsergeyu@chromium.org std::max(0, std::min(size.height(), static_cast<int>(nshotspot.y)))); 2392873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CGImageRef cg_image = 2402873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org [nsimage CGImageForProposedRect:NULL context:nil hints:nil]; 2412873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org if (!cg_image) 2422873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org return; 2432873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 2442873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org if (CGImageGetBitsPerPixel(cg_image) != DesktopFrame::kBytesPerPixel * 8 || 2452873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CGImageGetBytesPerRow(cg_image) != 2462873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org static_cast<size_t>(DesktopFrame::kBytesPerPixel * size.width()) || 2472873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CGImageGetBitsPerComponent(cg_image) != 8) { 2482873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org return; 2492873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org } 2502873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 2512873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CGDataProviderRef provider = CGImageGetDataProvider(cg_image); 2522873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CFDataRef image_data_ref = CGDataProviderCopyData(provider); 2532873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org if (image_data_ref == NULL) 2542873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org return; 2552873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 2562873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org const uint8_t* src_data = 2572873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org reinterpret_cast<const uint8_t*>(CFDataGetBytePtr(image_data_ref)); 2582873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 2592873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org // Compare the cursor with the previous one. 2602873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org if (last_cursor_.get() && 261eb9ce11063d614e6f3ac6d7dfb81eceb79329bc1sergeyu@chromium.org last_cursor_->image()->size().equals(size) && 2622873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org last_cursor_->hotspot().equals(hotspot) && 263eb9ce11063d614e6f3ac6d7dfb81eceb79329bc1sergeyu@chromium.org memcmp(last_cursor_->image()->data(), src_data, 264eb9ce11063d614e6f3ac6d7dfb81eceb79329bc1sergeyu@chromium.org last_cursor_->image()->stride() * size.height()) == 0) { 2655f5cbf2dae26ba0eaf13158d831691d2356dda90sergeyu@chromium.org CFRelease(image_data_ref); 2662873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org return; 2672873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org } 2682873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 2692873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org // Create a MouseCursor that describes the cursor and pass it to 2702873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org // the client. 2712873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org scoped_ptr<DesktopFrame> image( 2722873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org new BasicDesktopFrame(DesktopSize(size.width(), size.height()))); 2732873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org memcpy(image->data(), src_data, 2742873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org size.width() * size.height() * DesktopFrame::kBytesPerPixel); 2752873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 2762873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org CFRelease(image_data_ref); 2772873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 2782873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org scoped_ptr<MouseCursor> cursor(new MouseCursor(image.release(), hotspot)); 2792873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org last_cursor_.reset(MouseCursor::CopyOf(*cursor)); 2802873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 2812873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org callback_->OnMouseCursor(cursor.release()); 2822873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org} 2832873c4c23513c84d6c822562c07c5e31fc3aa7bbsergeyu@chromium.org 284af54d4b3a12f79ebcfe10695a8ec2b1da80ab1f4sergeyu@chromium.orgMouseCursorMonitor* MouseCursorMonitor::CreateForWindow( 285af54d4b3a12f79ebcfe10695a8ec2b1da80ab1f4sergeyu@chromium.org const DesktopCaptureOptions& options, WindowId window) { 2861d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org return new MouseCursorMonitorMac(options, window, kInvalidScreenId); 287af54d4b3a12f79ebcfe10695a8ec2b1da80ab1f4sergeyu@chromium.org} 288af54d4b3a12f79ebcfe10695a8ec2b1da80ab1f4sergeyu@chromium.org 289af54d4b3a12f79ebcfe10695a8ec2b1da80ab1f4sergeyu@chromium.orgMouseCursorMonitor* MouseCursorMonitor::CreateForScreen( 290a2c26549012b8024442fe0920d0325aa853d7890jiayl@webrtc.org const DesktopCaptureOptions& options, 291a2c26549012b8024442fe0920d0325aa853d7890jiayl@webrtc.org ScreenId screen) { 2921d23d5eec85f4b124b4941f7d583e52a85ad5deejiayl@webrtc.org return new MouseCursorMonitorMac(options, kCGNullWindowID, screen); 293af54d4b3a12f79ebcfe10695a8ec2b1da80ab1f4sergeyu@chromium.org} 294af54d4b3a12f79ebcfe10695a8ec2b1da80ab1f4sergeyu@chromium.org 295af54d4b3a12f79ebcfe10695a8ec2b1da80ab1f4sergeyu@chromium.org} // namespace webrtc 296