window_capturer_mac.mm revision d402875fa50164c6533ef0f7b2098f73eb94b8a8
1b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org/*
2b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
3b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org *
4b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org *  Use of this source code is governed by a BSD-style license
5b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org *  that can be found in the LICENSE file in the root of the source
6b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org *  tree. An additional intellectual property rights grant can be found
7b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org *  in the file PATENTS.  All contributing project authors may
8b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org *  be found in the AUTHORS file in the root of the source tree.
9b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org */
10b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
11b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org#include "webrtc/modules/desktop_capture/window_capturer.h"
12b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
1312dc1a38ca54a000e4fecfbc6d41138b895c9ca5pbos@webrtc.org#include <assert.h>
14eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org#include <ApplicationServices/ApplicationServices.h>
15886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org#include <Cocoa/Cocoa.h>
16eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org#include <CoreFoundation/CoreFoundation.h>
17b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
1812b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org#include "webrtc/base/macutils.h"
1912b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org#include "webrtc/modules/desktop_capture/desktop_capture_options.h"
20b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org#include "webrtc/modules/desktop_capture/desktop_frame.h"
2112b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org#include "webrtc/modules/desktop_capture/mac/desktop_configuration.h"
2212b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org#include "webrtc/modules/desktop_capture/mac/full_screen_chrome_window_detector.h"
2312b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org#include "webrtc/modules/desktop_capture/mac/window_list_utils.h"
24eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org#include "webrtc/system_wrappers/interface/logging.h"
2512b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org#include "webrtc/system_wrappers/interface/scoped_refptr.h"
2612b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org#include "webrtc/system_wrappers/interface/tick_util.h"
27b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
28b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgnamespace webrtc {
29b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
30b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgnamespace {
31b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
3212b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org// Returns true if the window exists.
33cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.orgbool IsWindowValid(CGWindowID id) {
34cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org  CFArrayRef window_id_array =
35cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org      CFArrayCreate(NULL, reinterpret_cast<const void **>(&id), 1, NULL);
36cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org  CFArrayRef window_array =
37cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org      CGWindowListCreateDescriptionFromArray(window_id_array);
38cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org  bool valid = window_array && CFArrayGetCount(window_array);
39cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org  CFRelease(window_id_array);
40cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org  CFRelease(window_array);
41cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org
42cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org  return valid;
43cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org}
44cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org
45b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgclass WindowCapturerMac : public WindowCapturer {
46b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org public:
4712b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org  explicit WindowCapturerMac(
4812b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org      scoped_refptr<FullScreenChromeWindowDetector>
4912b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org          full_screen_chrome_window_detector);
50b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  virtual ~WindowCapturerMac();
51b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
52b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // WindowCapturer interface.
53b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  virtual bool GetWindowList(WindowList* windows) OVERRIDE;
54b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  virtual bool SelectWindow(WindowId id) OVERRIDE;
55886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  virtual bool BringSelectedWindowToFront() OVERRIDE;
56b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
57b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  // DesktopCapturer interface.
58b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  virtual void Start(Callback* callback) OVERRIDE;
59b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  virtual void Capture(const DesktopRegion& region) OVERRIDE;
60b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
61b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org private:
62b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  Callback* callback_;
6312b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org
6412b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org  // The window being captured.
65eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org  CGWindowID window_id_;
66b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
6712b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org  scoped_refptr<FullScreenChromeWindowDetector>
6812b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org      full_screen_chrome_window_detector_;
6912b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org
70b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  DISALLOW_COPY_AND_ASSIGN(WindowCapturerMac);
71b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org};
72b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
7312b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.orgWindowCapturerMac::WindowCapturerMac(
7412b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org    scoped_refptr<FullScreenChromeWindowDetector>
7512b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org        full_screen_chrome_window_detector)
76eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org    : callback_(NULL),
7712b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org      window_id_(0),
7812b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org      full_screen_chrome_window_detector_(full_screen_chrome_window_detector) {
79b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}
80b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
81b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgWindowCapturerMac::~WindowCapturerMac() {
82b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}
83b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
84b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgbool WindowCapturerMac::GetWindowList(WindowList* windows) {
85eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org  // Only get on screen, non-desktop windows.
86eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org  CFArrayRef window_array = CGWindowListCopyWindowInfo(
87eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org      kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements,
88eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org      kCGNullWindowID);
89eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org  if (!window_array)
90eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org    return false;
91eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org
92eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org  // Check windows to make sure they have an id, title, and use window layer
93eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org  // other than 0.
94eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org  CFIndex count = CFArrayGetCount(window_array);
95eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org  for (CFIndex i = 0; i < count; ++i) {
96eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org    CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>(
97eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org        CFArrayGetValueAtIndex(window_array, i));
98eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org    CFStringRef window_title = reinterpret_cast<CFStringRef>(
99eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org        CFDictionaryGetValue(window, kCGWindowName));
100eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org    CFNumberRef window_id = reinterpret_cast<CFNumberRef>(
101eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org        CFDictionaryGetValue(window, kCGWindowNumber));
102eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org    CFNumberRef window_layer = reinterpret_cast<CFNumberRef>(
103eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org        CFDictionaryGetValue(window, kCGWindowLayer));
104eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org    if (window_title && window_id && window_layer) {
105eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org      // Skip windows with layer=0 (menu, dock).
106eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org      int layer;
107eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org      CFNumberGetValue(window_layer, kCFNumberIntType, &layer);
108eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org      if (layer != 0)
109eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org        continue;
110eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org
111eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org      int id;
112eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org      CFNumberGetValue(window_id, kCFNumberIntType, &id);
113eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org      WindowCapturer::Window window;
114eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org      window.id = id;
11512b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org      if (!rtc::ToUtf8(window_title, &(window.title)) ||
116eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org          window.title.empty()) {
117eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org        continue;
118eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org      }
119eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org      windows->push_back(window);
120eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org    }
121eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org  }
122eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org
123eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org  CFRelease(window_array);
124eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org  return true;
125b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}
126b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
127b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgbool WindowCapturerMac::SelectWindow(WindowId id) {
128cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org  if (!IsWindowValid(id))
129eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org    return false;
130eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org  window_id_ = id;
131eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org  return true;
132b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}
133b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
134886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.orgbool WindowCapturerMac::BringSelectedWindowToFront() {
135886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  if (!window_id_)
136886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org    return false;
137886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org
138886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  CGWindowID ids[1];
139886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  ids[0] = window_id_;
140886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  CFArrayRef window_id_array =
141886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org      CFArrayCreate(NULL, reinterpret_cast<const void **>(&ids), 1, NULL);
142886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org
143886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  CFArrayRef window_array =
144886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org      CGWindowListCreateDescriptionFromArray(window_id_array);
145886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  if (window_array == NULL || 0 == CFArrayGetCount(window_array)) {
146886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org    // Could not find the window. It might have been closed.
147886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org    LOG(LS_INFO) << "Window not found";
148886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org    CFRelease(window_id_array);
149886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org    return false;
150886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  }
151886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org
152886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>(
153886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org      CFArrayGetValueAtIndex(window_array, 0));
154886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  CFNumberRef pid_ref = reinterpret_cast<CFNumberRef>(
155886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org      CFDictionaryGetValue(window, kCGWindowOwnerPID));
156886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org
157886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  int pid;
158886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  CFNumberGetValue(pid_ref, kCFNumberIntType, &pid);
159886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org
160886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  // TODO(jiayl): this will bring the process main window to the front. We
161886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  // should find a way to bring only the window to the front.
162886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  bool result =
163886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org      [[NSRunningApplication runningApplicationWithProcessIdentifier: pid]
164886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org          activateWithOptions: NSApplicationActivateIgnoringOtherApps];
165886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org
166886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  CFRelease(window_id_array);
167886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  CFRelease(window_array);
168886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org  return result;
169886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org}
170886c94f07cf0a841b81cf9e69783bb1052d9c8a9jiayl@webrtc.org
171b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgvoid WindowCapturerMac::Start(Callback* callback) {
172b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  assert(!callback_);
173b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  assert(callback);
174b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
175b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org  callback_ = callback;
176b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}
177b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
178b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.orgvoid WindowCapturerMac::Capture(const DesktopRegion& region) {
179cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org  if (!IsWindowValid(window_id_)) {
180cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org    callback_->OnCaptureCompleted(NULL);
181cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org    return;
182cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org  }
183cc1ba15fe737bfc58ef279d50d7e713cbd8b9310jiayl@webrtc.org
18412b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org  CGWindowID on_screen_window = window_id_;
18512b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org  if (full_screen_chrome_window_detector_) {
18612b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org    CGWindowID full_screen_window =
18712b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org        full_screen_chrome_window_detector_->FindFullScreenWindow(window_id_);
18812b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org
18912b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org    if (full_screen_window != kCGNullWindowID)
19012b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org      on_screen_window = full_screen_window;
19112b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org  }
19212b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org
193eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org  CGImageRef window_image = CGWindowListCreateImage(
194eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org      CGRectNull, kCGWindowListOptionIncludingWindow,
19512b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org      on_screen_window, kCGWindowImageBoundsIgnoreFraming);
196eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org
197eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org  if (!window_image) {
198eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org    callback_->OnCaptureCompleted(NULL);
199eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org    return;
200eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org  }
201eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org
202eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org  int bits_per_pixel = CGImageGetBitsPerPixel(window_image);
203eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org  if (bits_per_pixel != 32) {
204eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org    LOG(LS_ERROR) << "Unsupported window image depth: " << bits_per_pixel;
205eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org    CFRelease(window_image);
206eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org    callback_->OnCaptureCompleted(NULL);
207eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org    return;
208eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org  }
209eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org
210eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org  int width = CGImageGetWidth(window_image);
211eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org  int height = CGImageGetHeight(window_image);
212eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org  CGDataProviderRef provider = CGImageGetDataProvider(window_image);
2132df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org  CFDataRef cf_data = CGDataProviderCopyData(provider);
2142df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org  DesktopFrame* frame = new BasicDesktopFrame(
2152df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org      DesktopSize(width, height));
2162df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org
2172df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org  int src_stride = CGImageGetBytesPerRow(window_image);
2182df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org  const uint8_t* src_data = CFDataGetBytePtr(cf_data);
2192df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org  for (int y = 0; y < height; ++y) {
2202df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org    memcpy(frame->data() + frame->stride() * y, src_data + src_stride * y,
2212df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org           DesktopFrame::kBytesPerPixel * width);
2222df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org  }
2232df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org
2242df89c0c8b6416c69d70da5f29615733986a0716sergeyu@chromium.org  CFRelease(cf_data);
225eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org  CFRelease(window_image);
226eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org
227d402875fa50164c6533ef0f7b2098f73eb94b8a8sergeyu@chromium.org  frame->mutable_updated_region()->SetRect(
228d402875fa50164c6533ef0f7b2098f73eb94b8a8sergeyu@chromium.org      DesktopRect::MakeSize(frame->size()));
229d402875fa50164c6533ef0f7b2098f73eb94b8a8sergeyu@chromium.org
230eef29ec6cf4389e0ce1c8b0336387bf1afb4a076sergeyu@chromium.org  callback_->OnCaptureCompleted(frame);
23112b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org
23212b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org  if (full_screen_chrome_window_detector_)
23312b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org    full_screen_chrome_window_detector_->UpdateWindowListIfNeeded(window_id_);
234b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}
235b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
236b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}  // namespace
237b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
238b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org// static
239894e6fe9ea16a63537ec6d453c81566d02f66059sergeyu@chromium.orgWindowCapturer* WindowCapturer::Create(const DesktopCaptureOptions& options) {
24012b4efefddc0ce727f228fd1a5024e70b4687ac4jiayl@webrtc.org  return new WindowCapturerMac(options.full_screen_chrome_window_detector());
241b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}
242b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org
243b10ccbec02db00fc17397afb72a115072590d391sergeyu@chromium.org}  // namespace webrtc
244