1 //===-- RNBServices.cpp -----------------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 //  Created by Christopher Friesen on 3/21/08.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #import "RNBServices.h"
15 
16 #import <CoreFoundation/CoreFoundation.h>
17 #import <unistd.h>
18 #import "DNBLog.h"
19 #include "MacOSX/CFUtils.h"
20 
21 #ifdef WITH_SPRINGBOARD
22 #import <SpringBoardServices/SpringBoardServices.h>
23 #endif
24 
25 int
26 ListApplications(std::string& plist, bool opt_runningApps, bool opt_debuggable)
27 {
28 #ifdef WITH_SPRINGBOARD
29     int result = -1;
30 
31     CFAllocatorRef alloc = kCFAllocatorDefault;
32 
33     // Create a mutable array that we can populate. Specify zero so it can be of any size.
34     CFReleaser<CFMutableArrayRef> plistMutableArray (::CFArrayCreateMutable (alloc, 0, &kCFTypeArrayCallBacks));
35 
36     CFReleaser<CFStringRef> sbsFrontAppID (::SBSCopyFrontmostApplicationDisplayIdentifier ());
37     CFReleaser<CFArrayRef> sbsAppIDs (::SBSCopyApplicationDisplayIdentifiers (opt_runningApps, opt_debuggable));
38 
39     // Need to check the return value from SBSCopyApplicationDisplayIdentifiers.
40     CFIndex count = sbsAppIDs.get() ? ::CFArrayGetCount (sbsAppIDs.get()) : 0;
41     CFIndex i = 0;
42     for (i = 0; i < count; i++)
43     {
44         CFStringRef displayIdentifier = (CFStringRef)::CFArrayGetValueAtIndex (sbsAppIDs.get(), i);
45 
46         // Create a new mutable dictionary for each application
47         CFReleaser<CFMutableDictionaryRef> appInfoDict (::CFDictionaryCreateMutable (alloc, 0, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
48 
49         // Get the process id for the app (if there is one)
50         pid_t pid = INVALID_NUB_PROCESS;
51         if (::SBSProcessIDForDisplayIdentifier ((CFStringRef)displayIdentifier, &pid) == true)
52         {
53             CFReleaser<CFNumberRef> pidCFNumber (::CFNumberCreate (alloc,  kCFNumberSInt32Type, &pid));
54             ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_PID_KEY, pidCFNumber.get());
55         }
56 
57         // Set the a boolean to indicate if this is the front most
58         if (sbsFrontAppID.get() && displayIdentifier && (::CFStringCompare (sbsFrontAppID.get(), displayIdentifier, 0) == kCFCompareEqualTo))
59             ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_FRONTMOST_KEY, kCFBooleanTrue);
60         else
61             ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_FRONTMOST_KEY, kCFBooleanFalse);
62 
63 
64         CFReleaser<CFStringRef> executablePath (::SBSCopyExecutablePathForDisplayIdentifier (displayIdentifier));
65         if (executablePath.get() != NULL)
66         {
67             ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_PATH_KEY, executablePath.get());
68         }
69 
70         CFReleaser<CFStringRef> iconImagePath (::SBSCopyIconImagePathForDisplayIdentifier (displayIdentifier)) ;
71         if (iconImagePath.get() != NULL)
72         {
73             ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_ICON_PATH_KEY, iconImagePath.get());
74         }
75 
76         CFReleaser<CFStringRef> localizedDisplayName (::SBSCopyLocalizedApplicationNameForDisplayIdentifier (displayIdentifier));
77         if (localizedDisplayName.get() != NULL)
78         {
79             ::CFDictionarySetValue (appInfoDict.get(), DTSERVICES_APP_DISPLAY_NAME_KEY, localizedDisplayName.get());
80         }
81 
82         // Append the application info to the plist array
83         ::CFArrayAppendValue (plistMutableArray.get(), appInfoDict.get());
84     }
85 
86     CFReleaser<CFDataRef> plistData (::CFPropertyListCreateXMLData (alloc, plistMutableArray.get()));
87 
88     // write plist to service port
89     if (plistData.get() != NULL)
90     {
91         CFIndex size = ::CFDataGetLength (plistData.get());
92         const UInt8 *bytes = ::CFDataGetBytePtr (plistData.get());
93         if (bytes != NULL && size > 0)
94         {
95             plist.assign((char *)bytes, size);
96             return 0;   // Success
97         }
98         else
99         {
100             DNBLogError("empty application property list.");
101             result = -2;
102         }
103     }
104     else
105     {
106         DNBLogError("serializing task list.");
107         result = -3;
108     }
109 
110     return result;
111 #else
112     // TODO: list all current processes
113     DNBLogError("SBS doesn't support getting application list.");
114     return -1;
115 #endif
116 }
117 
118 
119 bool
120 IsSBProcess (nub_process_t pid)
121 {
122 #ifdef WITH_SPRINGBOARD
123     bool opt_runningApps = true;
124     bool opt_debuggable = false;
125 
126     CFReleaser<CFArrayRef> sbsAppIDs (::SBSCopyApplicationDisplayIdentifiers (opt_runningApps, opt_debuggable));
127     if (sbsAppIDs.get() != NULL)
128     {
129         CFIndex count = ::CFArrayGetCount (sbsAppIDs.get());
130         CFIndex i = 0;
131         for (i = 0; i < count; i++)
132         {
133             CFStringRef displayIdentifier = (CFStringRef)::CFArrayGetValueAtIndex (sbsAppIDs.get(), i);
134 
135             // Get the process id for the app (if there is one)
136             pid_t sbs_pid = INVALID_NUB_PROCESS;
137             if (::SBSProcessIDForDisplayIdentifier ((CFStringRef)displayIdentifier, &sbs_pid) == TRUE)
138             {
139                 if (sbs_pid == pid)
140                     return true;
141             }
142         }
143     }
144 #endif
145     return false;
146 }
147 
148