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