147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org/*
247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  Copyright 2010 The WebRTC Project Authors. All rights reserved.
347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *
447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  Use of this source code is governed by a BSD-style license
547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  that can be found in the LICENSE file in the root of the source
647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  tree. An additional intellectual property rights grant can be found
747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  in the file PATENTS.  All contributing project authors may
847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org *  be found in the AUTHORS file in the root of the source tree.
947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org */
1047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/macwindowpicker.h"
1147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <ApplicationServices/ApplicationServices.h>
1347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <CoreFoundation/CoreFoundation.h>
1447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include <dlfcn.h>
1547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/logging.h"
1747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org#include "webrtc/base/macutils.h"
1847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
1947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgnamespace rtc {
2047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic const char* kCoreGraphicsName =
2247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    "/System/Library/Frameworks/ApplicationServices.framework/Frameworks/"
2347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    "CoreGraphics.framework/CoreGraphics";
2447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic const char* kWindowListCopyWindowInfo = "CGWindowListCopyWindowInfo";
2647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgstatic const char* kWindowListCreateDescriptionFromArray =
2747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    "CGWindowListCreateDescriptionFromArray";
2847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
2947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Function pointer for holding the CGWindowListCopyWindowInfo function.
3047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgtypedef CFArrayRef(*CGWindowListCopyWindowInfoProc)(CGWindowListOption,
3147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                                    CGWindowID);
3247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
3347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// Function pointer for holding the CGWindowListCreateDescriptionFromArray
3447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org// function.
3547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgtypedef CFArrayRef(*CGWindowListCreateDescriptionFromArrayProc)(CFArrayRef);
3647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
3747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgMacWindowPicker::MacWindowPicker() : lib_handle_(NULL), get_window_list_(NULL),
3847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                     get_window_list_desc_(NULL) {
3947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
4047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
4147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgMacWindowPicker::~MacWindowPicker() {
4247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (lib_handle_ != NULL) {
4347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    dlclose(lib_handle_);
4447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
4547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
4647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
4747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool MacWindowPicker::Init() {
4847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // TODO: If this class grows to use more dynamically functions
4947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // from the CoreGraphics framework, consider using
5047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // webrtc/base/latebindingsymboltable.h.
5147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  lib_handle_ = dlopen(kCoreGraphicsName, RTLD_NOW);
5247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (lib_handle_ == NULL) {
5347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_ERROR) << "Could not load CoreGraphics";
5447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
5547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
5647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
5747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  get_window_list_ = dlsym(lib_handle_, kWindowListCopyWindowInfo);
5847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  get_window_list_desc_ =
5947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      dlsym(lib_handle_, kWindowListCreateDescriptionFromArray);
6047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (get_window_list_ == NULL || get_window_list_desc_ == NULL) {
6147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // The CGWindowListCopyWindowInfo and the
6247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // CGWindowListCreateDescriptionFromArray functions was introduced
6347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // in Leopard(10.5) so this is a normal failure on Tiger.
6447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_INFO) << "Failed to load Core Graphics symbols";
6547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    dlclose(lib_handle_);
6647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    lib_handle_ = NULL;
6747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
6847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
6947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
7047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return true;
7147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
7247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
7347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool MacWindowPicker::IsVisible(const WindowId& id) {
7447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Init if we're not already inited.
7547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (get_window_list_desc_ == NULL && !Init()) {
7647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
7747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
7847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CGWindowID ids[1];
7947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ids[0] = id.id();
8047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CFArrayRef window_id_array =
8147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      CFArrayCreate(NULL, reinterpret_cast<const void **>(&ids), 1, NULL);
8247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
8347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CFArrayRef window_array =
8447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      reinterpret_cast<CGWindowListCreateDescriptionFromArrayProc>(
8547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          get_window_list_desc_)(window_id_array);
8647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (window_array == NULL || 0 == CFArrayGetCount(window_array)) {
8747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Could not find the window. It might have been closed.
8847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_INFO) << "Window not found";
8947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFRelease(window_id_array);
9047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
9147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
9247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
9347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>(
9447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      CFArrayGetValueAtIndex(window_array, 0));
9547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CFBooleanRef is_visible = reinterpret_cast<CFBooleanRef>(
9647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      CFDictionaryGetValue(window, kCGWindowIsOnscreen));
9747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
9847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Check that the window is visible. If not we might crash.
9947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  bool visible = false;
10047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (is_visible != NULL) {
10147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    visible = CFBooleanGetValue(is_visible);
10247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
10347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CFRelease(window_id_array);
10447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CFRelease(window_array);
10547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return visible;
10647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
10747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
10847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool MacWindowPicker::MoveToFront(const WindowId& id) {
10947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Init if we're not already initialized.
11047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (get_window_list_desc_ == NULL && !Init()) {
11147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
11247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
11347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CGWindowID ids[1];
11447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ids[0] = id.id();
11547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CFArrayRef window_id_array =
11647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      CFArrayCreate(NULL, reinterpret_cast<const void **>(&ids), 1, NULL);
11747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
11847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CFArrayRef window_array =
11947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      reinterpret_cast<CGWindowListCreateDescriptionFromArrayProc>(
12047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          get_window_list_desc_)(window_id_array);
12147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (window_array == NULL || 0 == CFArrayGetCount(window_array)) {
12247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // Could not find the window. It might have been closed.
12347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG(LS_INFO) << "Window not found";
12447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFRelease(window_id_array);
12547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
12647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
12747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
12847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>(
12947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      CFArrayGetValueAtIndex(window_array, 0));
13047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CFStringRef window_name_ref = reinterpret_cast<CFStringRef>(
13147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      CFDictionaryGetValue(window, kCGWindowName));
13247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CFNumberRef application_pid = reinterpret_cast<CFNumberRef>(
13347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      CFDictionaryGetValue(window, kCGWindowOwnerPID));
13447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
13547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  int pid_val;
13647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CFNumberGetValue(application_pid, kCFNumberIntType, &pid_val);
13747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  std::string window_name;
13847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ToUtf8(window_name_ref, &window_name);
13947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
14047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Build an applescript that sets the selected window to front
14147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // within the application. Then set the application to front.
14247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  bool result = true;
14347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  std::stringstream ss;
14447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  ss << "tell application \"System Events\"\n"
14547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org     << "set proc to the first item of (every process whose unix id is "
14647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org     << pid_val
14747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org     << ")\n"
14847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org     << "tell proc to perform action \"AXRaise\" of window \""
14947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org     << window_name
15047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org     << "\"\n"
15147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org     << "set the frontmost of proc to true\n"
15247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org     << "end tell";
15347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (!RunAppleScript(ss.str())) {
15447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // This might happen to for example X applications where the X
15547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // server spawns of processes with their own PID but the X server
15647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // is still registered as owner to the application windows. As a
15747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // workaround, we put the X server process to front, meaning that
15847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // all X applications will show up. The drawback with this
15947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // workaround is that the application that we really wanted to set
16047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // to front might be behind another X application.
16147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    ProcessSerialNumber psn;
16247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    pid_t pid = pid_val;
16347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    int res = GetProcessForPID(pid, &psn);
16447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (res != 0) {
16547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      LOG(LS_ERROR) << "Failed getting process for pid";
16647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      result = false;
16747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
16847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    res = SetFrontProcess(&psn);
16947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (res != 0) {
17047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      LOG(LS_ERROR) << "Failed setting process to front";
17147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      result = false;
17247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
17347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
17447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CFRelease(window_id_array);
17547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CFRelease(window_array);
17647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return result;
17747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
17847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
17947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool MacWindowPicker::GetDesktopList(DesktopDescriptionList* descriptions) {
18047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  const uint32_t kMaxDisplays = 128;
18147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CGDirectDisplayID active_displays[kMaxDisplays];
18247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  uint32_t display_count = 0;
18347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
18447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CGError err = CGGetActiveDisplayList(kMaxDisplays,
18547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                       active_displays,
18647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                       &display_count);
18747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (err != kCGErrorSuccess) {
18847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    LOG_E(LS_ERROR, OS, err) << "Failed to enumerate the active displays.";
18947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
19047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
19147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  for (uint32_t i = 0; i < display_count; ++i) {
19247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    DesktopId id(active_displays[i], static_cast<int>(i));
19347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    // TODO: Figure out an appropriate desktop title.
19447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    DesktopDescription desc(id, "");
19547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    desc.set_primary(CGDisplayIsMain(id.id()));
19647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    descriptions->push_back(desc);
19747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
19847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return display_count > 0;
19947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
20047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
20147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool MacWindowPicker::GetDesktopDimensions(const DesktopId& id,
20247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                           int* width,
20347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org                                           int* height) {
20447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  *width = CGDisplayPixelsWide(id.id());
20547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  *height = CGDisplayPixelsHigh(id.id());
20647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return true;
20747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
20847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
20947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.orgbool MacWindowPicker::GetWindowList(WindowDescriptionList* descriptions) {
21047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Init if we're not already inited.
21147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (get_window_list_ == NULL && !Init()) {
21247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
21347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
21447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
21547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Only get onscreen, non-desktop windows.
21647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CFArrayRef window_array =
21747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      reinterpret_cast<CGWindowListCopyWindowInfoProc>(get_window_list_)(
21847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements,
21947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org          kCGNullWindowID);
22047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  if (window_array == NULL) {
22147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    return false;
22247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
22347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
22447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  // Check windows to make sure they have an id, title, and use window layer 0.
22547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CFIndex i;
22647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CFIndex count = CFArrayGetCount(window_array);
22747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  for (i = 0; i < count; ++i) {
22847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>(
22947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        CFArrayGetValueAtIndex(window_array, i));
23047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFStringRef window_title = reinterpret_cast<CFStringRef>(
23147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        CFDictionaryGetValue(window, kCGWindowName));
23247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFNumberRef window_id = reinterpret_cast<CFNumberRef>(
23347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        CFDictionaryGetValue(window, kCGWindowNumber));
23447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    CFNumberRef window_layer = reinterpret_cast<CFNumberRef>(
23547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        CFDictionaryGetValue(window, kCGWindowLayer));
23647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    if (window_title != NULL && window_id != NULL && window_layer != NULL) {
23747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      std::string title_str;
23847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      int id_val, layer_val;
23947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      ToUtf8(window_title, &title_str);
24047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      CFNumberGetValue(window_id, kCFNumberIntType, &id_val);
24147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      CFNumberGetValue(window_layer, kCFNumberIntType, &layer_val);
24247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
24347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      // Discard windows without a title.
24447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      if (layer_val == 0 && title_str.length() > 0) {
24547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        WindowId id(static_cast<CGWindowID>(id_val));
24647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        WindowDescription desc(id, title_str);
24747be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org        descriptions->push_back(desc);
24847be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org      }
24947be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org    }
25047be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  }
25147be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
25247be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  CFRelease(window_array);
25347be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org  return true;
25447be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}
25547be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org
25647be73b8629244d6bb63a28198f97f040ce53d21henrike@webrtc.org}  // namespace rtc
257