| OLD | NEW |
| (Empty) |
| 1 /* | |
| 2 * Copyright 2010 The WebRTC Project Authors. All rights reserved. | |
| 3 * | |
| 4 * Use of this source code is governed by a BSD-style license | |
| 5 * that can be found in the LICENSE file in the root of the source | |
| 6 * tree. An additional intellectual property rights grant can be found | |
| 7 * in the file PATENTS. All contributing project authors may | |
| 8 * be found in the AUTHORS file in the root of the source tree. | |
| 9 */ | |
| 10 #include "webrtc/base/macwindowpicker.h" | |
| 11 | |
| 12 #include <ApplicationServices/ApplicationServices.h> | |
| 13 #include <CoreFoundation/CoreFoundation.h> | |
| 14 #include <dlfcn.h> | |
| 15 | |
| 16 #include "webrtc/base/logging.h" | |
| 17 #include "webrtc/base/macutils.h" | |
| 18 | |
| 19 namespace rtc { | |
| 20 | |
| 21 static const char* kCoreGraphicsName = | |
| 22 "/System/Library/Frameworks/ApplicationServices.framework/Frameworks/" | |
| 23 "CoreGraphics.framework/CoreGraphics"; | |
| 24 | |
| 25 static const char* kWindowListCopyWindowInfo = "CGWindowListCopyWindowInfo"; | |
| 26 static const char* kWindowListCreateDescriptionFromArray = | |
| 27 "CGWindowListCreateDescriptionFromArray"; | |
| 28 | |
| 29 // Function pointer for holding the CGWindowListCopyWindowInfo function. | |
| 30 typedef CFArrayRef(*CGWindowListCopyWindowInfoProc)(CGWindowListOption, | |
| 31 CGWindowID); | |
| 32 | |
| 33 // Function pointer for holding the CGWindowListCreateDescriptionFromArray | |
| 34 // function. | |
| 35 typedef CFArrayRef(*CGWindowListCreateDescriptionFromArrayProc)(CFArrayRef); | |
| 36 | |
| 37 MacWindowPicker::MacWindowPicker() : lib_handle_(NULL), get_window_list_(NULL), | |
| 38 get_window_list_desc_(NULL) { | |
| 39 } | |
| 40 | |
| 41 MacWindowPicker::~MacWindowPicker() { | |
| 42 if (lib_handle_ != NULL) { | |
| 43 dlclose(lib_handle_); | |
| 44 } | |
| 45 } | |
| 46 | |
| 47 bool MacWindowPicker::Init() { | |
| 48 // TODO: If this class grows to use more dynamically functions | |
| 49 // from the CoreGraphics framework, consider using | |
| 50 // webrtc/base/latebindingsymboltable.h. | |
| 51 lib_handle_ = dlopen(kCoreGraphicsName, RTLD_NOW); | |
| 52 if (lib_handle_ == NULL) { | |
| 53 LOG(LS_ERROR) << "Could not load CoreGraphics"; | |
| 54 return false; | |
| 55 } | |
| 56 | |
| 57 get_window_list_ = dlsym(lib_handle_, kWindowListCopyWindowInfo); | |
| 58 get_window_list_desc_ = | |
| 59 dlsym(lib_handle_, kWindowListCreateDescriptionFromArray); | |
| 60 if (get_window_list_ == NULL || get_window_list_desc_ == NULL) { | |
| 61 // The CGWindowListCopyWindowInfo and the | |
| 62 // CGWindowListCreateDescriptionFromArray functions was introduced | |
| 63 // in Leopard(10.5) so this is a normal failure on Tiger. | |
| 64 LOG(LS_INFO) << "Failed to load Core Graphics symbols"; | |
| 65 dlclose(lib_handle_); | |
| 66 lib_handle_ = NULL; | |
| 67 return false; | |
| 68 } | |
| 69 | |
| 70 return true; | |
| 71 } | |
| 72 | |
| 73 bool MacWindowPicker::IsVisible(const WindowId& id) { | |
| 74 // Init if we're not already inited. | |
| 75 if (get_window_list_desc_ == NULL && !Init()) { | |
| 76 return false; | |
| 77 } | |
| 78 CGWindowID ids[1]; | |
| 79 ids[0] = id.id(); | |
| 80 CFArrayRef window_id_array = | |
| 81 CFArrayCreate(NULL, reinterpret_cast<const void **>(&ids), 1, NULL); | |
| 82 | |
| 83 CFArrayRef window_array = | |
| 84 reinterpret_cast<CGWindowListCreateDescriptionFromArrayProc>( | |
| 85 get_window_list_desc_)(window_id_array); | |
| 86 if (window_array == NULL || 0 == CFArrayGetCount(window_array)) { | |
| 87 // Could not find the window. It might have been closed. | |
| 88 LOG(LS_INFO) << "Window not found"; | |
| 89 CFRelease(window_id_array); | |
| 90 return false; | |
| 91 } | |
| 92 | |
| 93 CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>( | |
| 94 CFArrayGetValueAtIndex(window_array, 0)); | |
| 95 CFBooleanRef is_visible = reinterpret_cast<CFBooleanRef>( | |
| 96 CFDictionaryGetValue(window, kCGWindowIsOnscreen)); | |
| 97 | |
| 98 // Check that the window is visible. If not we might crash. | |
| 99 bool visible = false; | |
| 100 if (is_visible != NULL) { | |
| 101 visible = CFBooleanGetValue(is_visible); | |
| 102 } | |
| 103 CFRelease(window_id_array); | |
| 104 CFRelease(window_array); | |
| 105 return visible; | |
| 106 } | |
| 107 | |
| 108 bool MacWindowPicker::MoveToFront(const WindowId& id) { | |
| 109 return false; | |
| 110 } | |
| 111 | |
| 112 bool MacWindowPicker::GetDesktopList(DesktopDescriptionList* descriptions) { | |
| 113 const uint32_t kMaxDisplays = 128; | |
| 114 CGDirectDisplayID active_displays[kMaxDisplays]; | |
| 115 uint32_t display_count = 0; | |
| 116 | |
| 117 CGError err = CGGetActiveDisplayList(kMaxDisplays, | |
| 118 active_displays, | |
| 119 &display_count); | |
| 120 if (err != kCGErrorSuccess) { | |
| 121 LOG_E(LS_ERROR, OS, err) << "Failed to enumerate the active displays."; | |
| 122 return false; | |
| 123 } | |
| 124 for (uint32_t i = 0; i < display_count; ++i) { | |
| 125 DesktopId id(active_displays[i], static_cast<int>(i)); | |
| 126 // TODO: Figure out an appropriate desktop title. | |
| 127 DesktopDescription desc(id, ""); | |
| 128 desc.set_primary(CGDisplayIsMain(id.id())); | |
| 129 descriptions->push_back(desc); | |
| 130 } | |
| 131 return display_count > 0; | |
| 132 } | |
| 133 | |
| 134 bool MacWindowPicker::GetDesktopDimensions(const DesktopId& id, | |
| 135 int* width, | |
| 136 int* height) { | |
| 137 *width = CGDisplayPixelsWide(id.id()); | |
| 138 *height = CGDisplayPixelsHigh(id.id()); | |
| 139 return true; | |
| 140 } | |
| 141 | |
| 142 bool MacWindowPicker::GetWindowList(WindowDescriptionList* descriptions) { | |
| 143 // Init if we're not already inited. | |
| 144 if (get_window_list_ == NULL && !Init()) { | |
| 145 return false; | |
| 146 } | |
| 147 | |
| 148 // Only get onscreen, non-desktop windows. | |
| 149 CFArrayRef window_array = | |
| 150 reinterpret_cast<CGWindowListCopyWindowInfoProc>(get_window_list_)( | |
| 151 kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, | |
| 152 kCGNullWindowID); | |
| 153 if (window_array == NULL) { | |
| 154 return false; | |
| 155 } | |
| 156 | |
| 157 // Check windows to make sure they have an id, title, and use window layer 0. | |
| 158 CFIndex i; | |
| 159 CFIndex count = CFArrayGetCount(window_array); | |
| 160 for (i = 0; i < count; ++i) { | |
| 161 CFDictionaryRef window = reinterpret_cast<CFDictionaryRef>( | |
| 162 CFArrayGetValueAtIndex(window_array, i)); | |
| 163 CFStringRef window_title = reinterpret_cast<CFStringRef>( | |
| 164 CFDictionaryGetValue(window, kCGWindowName)); | |
| 165 CFNumberRef window_id = reinterpret_cast<CFNumberRef>( | |
| 166 CFDictionaryGetValue(window, kCGWindowNumber)); | |
| 167 CFNumberRef window_layer = reinterpret_cast<CFNumberRef>( | |
| 168 CFDictionaryGetValue(window, kCGWindowLayer)); | |
| 169 if (window_title != NULL && window_id != NULL && window_layer != NULL) { | |
| 170 std::string title_str; | |
| 171 int id_val, layer_val; | |
| 172 ToUtf8(window_title, &title_str); | |
| 173 CFNumberGetValue(window_id, kCFNumberIntType, &id_val); | |
| 174 CFNumberGetValue(window_layer, kCFNumberIntType, &layer_val); | |
| 175 | |
| 176 // Discard windows without a title. | |
| 177 if (layer_val == 0 && title_str.length() > 0) { | |
| 178 WindowId id(static_cast<CGWindowID>(id_val)); | |
| 179 WindowDescription desc(id, title_str); | |
| 180 descriptions->push_back(desc); | |
| 181 } | |
| 182 } | |
| 183 } | |
| 184 | |
| 185 CFRelease(window_array); | |
| 186 return true; | |
| 187 } | |
| 188 | |
| 189 } // namespace rtc | |
| OLD | NEW |