15976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Copyright 2010 Google Inc. All Rights Reserved
25976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
35976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
45976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/macwindowpicker.h"
55976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
65976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <ApplicationServices/ApplicationServices.h>
75976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <CoreFoundation/CoreFoundation.h>
85976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include <dlfcn.h>
95976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/logging.h"
115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org#include "talk/base/macutils.h"
125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgnamespace talk_base {
145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const char* kCoreGraphicsName =
165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    "/System/Library/Frameworks/ApplicationServices.framework/Frameworks/"
175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    "CoreGraphics.framework/CoreGraphics";
185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const char* kWindowListCopyWindowInfo = "CGWindowListCopyWindowInfo";
205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgstatic const char* kWindowListCreateDescriptionFromArray =
215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    "CGWindowListCreateDescriptionFromArray";
225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Function pointer for holding the CGWindowListCopyWindowInfo function.
245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgtypedef CFArrayRef(*CGWindowListCopyWindowInfoProc)(CGWindowListOption,
255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                                    CGWindowID);
265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// Function pointer for holding the CGWindowListCreateDescriptionFromArray
285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org// function.
295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgtypedef CFArrayRef(*CGWindowListCreateDescriptionFromArrayProc)(CFArrayRef);
305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgMacWindowPicker::MacWindowPicker() : lib_handle_(NULL), get_window_list_(NULL),
325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                     get_window_list_desc_(NULL) {
335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgMacWindowPicker::~MacWindowPicker() {
365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (lib_handle_ != NULL) {
375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    dlclose(lib_handle_);
385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool MacWindowPicker::Init() {
425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // TODO: If this class grows to use more dynamically functions
435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // from the CoreGraphics framework, consider using
445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // talk/base/latebindingsymboltable.h.
455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  lib_handle_ = dlopen(kCoreGraphicsName, RTLD_NOW);
465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (lib_handle_ == NULL) {
475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_ERROR) << "Could not load CoreGraphics";
485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  get_window_list_ = dlsym(lib_handle_, kWindowListCopyWindowInfo);
525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  get_window_list_desc_ =
535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      dlsym(lib_handle_, kWindowListCreateDescriptionFromArray);
545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (get_window_list_ == NULL || get_window_list_desc_ == NULL) {
555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // The CGWindowListCopyWindowInfo and the
565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // CGWindowListCreateDescriptionFromArray functions was introduced
575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // in Leopard(10.5) so this is a normal failure on Tiger.
585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_INFO) << "Failed to load Core Graphics symbols";
595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    dlclose(lib_handle_);
605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    lib_handle_ = NULL;
615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool MacWindowPicker::IsVisible(const WindowId& id) {
685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Init if we're not already inited.
695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (get_window_list_desc_ == NULL && !Init()) {
705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CGWindowID ids[1];
735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ids[0] = id.id();
745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CFArrayRef window_id_array =
755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      CFArrayCreate(NULL, reinterpret_cast<const void **>(&ids), 1, NULL);
765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CFArrayRef window_array =
785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      reinterpret_cast<CGWindowListCreateDescriptionFromArrayProc>(
795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          get_window_list_desc_)(window_id_array);
805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (window_array == NULL || 0 == CFArrayGetCount(window_array)) {
815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Could not find the window. It might have been closed.
825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_INFO) << "Window not found";
835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    CFRelease(window_id_array);
845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>(
885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      CFArrayGetValueAtIndex(window_array, 0));
895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CFBooleanRef is_visible = reinterpret_cast<CFBooleanRef>(
905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      CFDictionaryGetValue(window, kCGWindowIsOnscreen));
915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Check that the window is visible. If not we might crash.
935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool visible = false;
945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (is_visible != NULL) {
955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    visible = CFBooleanGetValue(is_visible);
965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CFRelease(window_id_array);
985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CFRelease(window_array);
995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return visible;
1005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool MacWindowPicker::MoveToFront(const WindowId& id) {
1035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Init if we're not already initialized.
1045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (get_window_list_desc_ == NULL && !Init()) {
1055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
1065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CGWindowID ids[1];
1085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ids[0] = id.id();
1095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CFArrayRef window_id_array =
1105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      CFArrayCreate(NULL, reinterpret_cast<const void **>(&ids), 1, NULL);
1115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CFArrayRef window_array =
1135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      reinterpret_cast<CGWindowListCreateDescriptionFromArrayProc>(
1145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          get_window_list_desc_)(window_id_array);
1155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (window_array == NULL || 0 == CFArrayGetCount(window_array)) {
1165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // Could not find the window. It might have been closed.
1175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG(LS_INFO) << "Window not found";
1185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    CFRelease(window_id_array);
1195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
1205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>(
1235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      CFArrayGetValueAtIndex(window_array, 0));
1245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CFStringRef window_name_ref = reinterpret_cast<CFStringRef>(
1255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      CFDictionaryGetValue(window, kCGWindowName));
1265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CFNumberRef application_pid = reinterpret_cast<CFNumberRef>(
1275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      CFDictionaryGetValue(window, kCGWindowOwnerPID));
1285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  int pid_val;
1305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CFNumberGetValue(application_pid, kCFNumberIntType, &pid_val);
1315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::string window_name;
1325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ToUtf8(window_name_ref, &window_name);
1335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Build an applescript that sets the selected window to front
1355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // within the application. Then set the application to front.
1365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  bool result = true;
1375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  std::stringstream ss;
1385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  ss << "tell application \"System Events\"\n"
1395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org     << "set proc to the first item of (every process whose unix id is "
1405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org     << pid_val
1415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org     << ")\n"
1425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org     << "tell proc to perform action \"AXRaise\" of window \""
1435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org     << window_name
1445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org     << "\"\n"
1455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org     << "set the frontmost of proc to true\n"
1465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org     << "end tell";
1475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (!RunAppleScript(ss.str())) {
1485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // This might happen to for example X applications where the X
1495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // server spawns of processes with their own PID but the X server
1505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // is still registered as owner to the application windows. As a
1515976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // workaround, we put the X server process to front, meaning that
1525976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // all X applications will show up. The drawback with this
1535976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // workaround is that the application that we really wanted to set
1545976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // to front might be behind another X application.
1555976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    ProcessSerialNumber psn;
1565976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    pid_t pid = pid_val;
1575976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    int res = GetProcessForPID(pid, &psn);
1585976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (res != 0) {
1595976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_ERROR) << "Failed getting process for pid";
1605976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      result = false;
1615976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
1625976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    res = SetFrontProcess(&psn);
1635976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (res != 0) {
1645976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      LOG(LS_ERROR) << "Failed setting process to front";
1655976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      result = false;
1665976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
1675976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1685976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CFRelease(window_id_array);
1695976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CFRelease(window_array);
1705976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return result;
1715976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1725976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1735976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool MacWindowPicker::GetDesktopList(DesktopDescriptionList* descriptions) {
1745976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  const uint32_t kMaxDisplays = 128;
1755976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CGDirectDisplayID active_displays[kMaxDisplays];
1765976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  uint32_t display_count = 0;
1775976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1785976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CGError err = CGGetActiveDisplayList(kMaxDisplays,
1795976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                       active_displays,
1805976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                       &display_count);
1815976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (err != kCGErrorSuccess) {
1825976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    LOG_E(LS_ERROR, OS, err) << "Failed to enumerate the active displays.";
1835976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
1845976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1855976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (uint32_t i = 0; i < display_count; ++i) {
1865976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    DesktopId id(active_displays[i], static_cast<int>(i));
1875976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    // TODO: Figure out an appropriate desktop title.
1885976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    DesktopDescription desc(id, "");
1895976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    desc.set_primary(CGDisplayIsMain(id.id()));
1905976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    descriptions->push_back(desc);
1915976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
1925976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return display_count > 0;
1935976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
1945976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
1955976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool MacWindowPicker::GetDesktopDimensions(const DesktopId& id,
1965976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                           int* width,
1975976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org                                           int* height) {
1985976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  *width = CGDisplayPixelsWide(id.id());
1995976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  *height = CGDisplayPixelsHigh(id.id());
2005976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
2015976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2025976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2035976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.orgbool MacWindowPicker::GetWindowList(WindowDescriptionList* descriptions) {
2045976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Init if we're not already inited.
2055976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (get_window_list_ == NULL && !Init()) {
2065976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
2075976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2085976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2095976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Only get onscreen, non-desktop windows.
2105976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CFArrayRef window_array =
2115976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      reinterpret_cast<CGWindowListCopyWindowInfoProc>(get_window_list_)(
2125976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements,
2135976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org          kCGNullWindowID);
2145976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  if (window_array == NULL) {
2155976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    return false;
2165976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2175976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2185976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  // Check windows to make sure they have an id, title, and use window layer 0.
2195976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CFIndex i;
2205976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CFIndex count = CFArrayGetCount(window_array);
2215976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  for (i = 0; i < count; ++i) {
2225976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>(
2235976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        CFArrayGetValueAtIndex(window_array, i));
2245976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    CFStringRef window_title = reinterpret_cast<CFStringRef>(
2255976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        CFDictionaryGetValue(window, kCGWindowName));
2265976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    CFNumberRef window_id = reinterpret_cast<CFNumberRef>(
2275976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        CFDictionaryGetValue(window, kCGWindowNumber));
2285976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    CFNumberRef window_layer = reinterpret_cast<CFNumberRef>(
2295976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        CFDictionaryGetValue(window, kCGWindowLayer));
2305976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    if (window_title != NULL && window_id != NULL && window_layer != NULL) {
2315976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      std::string title_str;
2325976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      int id_val, layer_val;
2335976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      ToUtf8(window_title, &title_str);
2345976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      CFNumberGetValue(window_id, kCFNumberIntType, &id_val);
2355976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      CFNumberGetValue(window_layer, kCFNumberIntType, &layer_val);
2365976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2375976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      // Discard windows without a title.
2385976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      if (layer_val == 0 && title_str.length() > 0) {
2395976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        WindowId id(static_cast<CGWindowID>(id_val));
2405976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        WindowDescription desc(id, title_str);
2415976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org        descriptions->push_back(desc);
2425976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org      }
2435976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org    }
2445976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  }
2455976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2465976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  CFRelease(window_array);
2475976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org  return true;
2485976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}
2495976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org
2505976650443d68ccfadf1dea24999ee459dd2819mflodman@webrtc.org}  // namespace talk_base
251