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 |