PageRenderTime 35ms CodeModel.GetById 13ms RepoModel.GetById 0ms app.codeStats 0ms

/core/externals/update-engine/externals/google-toolbox-for-mac/AppKit/GTMNSWorkspace+Running.m

http://macfuse.googlecode.com/
Objective C | 291 lines | 230 code | 32 blank | 29 comment | 28 complexity | 8e52e324b2cb19a16bddbe1e246ef2e0 MD5 | raw file
Possible License(s): Apache-2.0, BSD-3-Clause, GPL-2.0
  1. //
  2. // GTMNSWorkspace+Running.m
  3. //
  4. // Copyright 2007-2008 Google Inc.
  5. //
  6. // Licensed under the Apache License, Version 2.0 (the "License"); you may not
  7. // use this file except in compliance with the License. You may obtain a copy
  8. // of the License at
  9. //
  10. // http://www.apache.org/licenses/LICENSE-2.0
  11. //
  12. // Unless required by applicable law or agreed to in writing, software
  13. // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
  14. // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
  15. // License for the specific language governing permissions and limitations under
  16. // the License.
  17. //
  18. #import "GTMNSWorkspace+Running.h"
  19. #import <Carbon/Carbon.h>
  20. #import <unistd.h>
  21. #import "GTMSystemVersion.h"
  22. NSString *const kGTMWorkspaceRunningPSN = @"PSN";
  23. NSString *const kGTMWorkspaceRunningFlavor = @"Flavor";
  24. NSString *const kGTMWorkspaceRunningAttributes = @"Attributes";
  25. NSString *const kGTMWorkspaceRunningParentPSN = @"ParentPSN";
  26. NSString *const kGTMWorkspaceRunningFileType = @"FileType";
  27. NSString *const kGTMWorkspaceRunningFileCreator = @"FileCreator";
  28. NSString *const kGTMWorkspaceRunningPID = @"pid";
  29. NSString *const kGTMWorkspaceRunningLSBackgroundOnly = @"LSBackgroundOnly";
  30. NSString *const kGTMWorkspaceRunningLSUIElement = @"LSUIElement";
  31. NSString *const kGTMWorkspaceRunningIsHidden = @"IsHiddenAttr";
  32. NSString *const kGTMWorkspaceRunningCheckedIn = @"IsCheckedInAttr";
  33. NSString *const kGTMWorkspaceRunningLSUIPresentationMode
  34. = @"LSUIPresentationMode";
  35. NSString *const kGTMWorkspaceRunningBundlePath = @"BundlePath";
  36. NSString *const kGTMWorkspaceRunningBundleVersion = @"CFBundleVersion";
  37. @interface GTMWorkspaceRunningApplicationList : NSObject {
  38. @private
  39. NSArray *launchedApps_;
  40. }
  41. + (GTMWorkspaceRunningApplicationList *)sharedApplicationList;
  42. - (NSArray *)launchedApplications;
  43. - (void)didLaunchOrTerminateApp:(NSNotification *)notification;
  44. @end
  45. @implementation NSWorkspace (GTMWorkspaceRunningAdditions)
  46. /// Returns a YES/NO if a process w/ the given identifier is running
  47. - (BOOL)gtm_isAppWithIdentifierRunning:(NSString *)identifier {
  48. if ([identifier length] == 0) return NO;
  49. NSArray *launchedApps = [self gtm_launchedApplications];
  50. NSArray *buildIDs
  51. = [launchedApps valueForKey:@"NSApplicationBundleIdentifier"];
  52. return [buildIDs containsObject:identifier];
  53. }
  54. - (NSDictionary *)gtm_processInfoDictionaryForPID:(pid_t)pid {
  55. NSDictionary *dict = nil;
  56. ProcessSerialNumber psn;
  57. if (GetProcessForPID(pid, &psn) == noErr) {
  58. dict = [self gtm_processInfoDictionaryForPSN:&psn];
  59. }
  60. return dict;
  61. }
  62. - (NSDictionary *)gtm_processInfoDictionaryForPSN:(ProcessSerialNumberPtr const)psn {
  63. NSDictionary *dict = nil;
  64. if (psn) {
  65. CFDictionaryRef cfDict
  66. = ProcessInformationCopyDictionary(psn,
  67. kProcessDictionaryIncludeAllInformationMask);
  68. dict = GTMCFAutorelease(cfDict);
  69. }
  70. return dict;
  71. }
  72. - (NSDictionary *)gtm_processInfoDictionary {
  73. NSDictionary *dict = nil;
  74. ProcessSerialNumber selfNumber;
  75. if (MacGetCurrentProcess(&selfNumber) == noErr) {
  76. dict = [self gtm_processInfoDictionaryForPSN:&selfNumber];
  77. }
  78. return dict;
  79. }
  80. - (NSDictionary *)gtm_processInfoDictionaryForActiveApp {
  81. NSDictionary *processDict = nil;
  82. ProcessSerialNumber psn;
  83. OSStatus status = GetFrontProcess(&psn);
  84. if (status == noErr) {
  85. processDict = [self gtm_processInfoDictionaryForPSN:&psn];
  86. }
  87. return processDict;
  88. }
  89. - (BOOL)gtm_wasLaunchedAsLoginItem {
  90. // If the launching process was 'loginwindow', we were launched as a login
  91. // item
  92. return [self gtm_wasLaunchedByProcess:@"com.apple.loginwindow"];
  93. }
  94. - (BOOL)gtm_wasLaunchedByProcess:(NSString*)bundleid {
  95. BOOL wasLaunchedByProcess = NO;
  96. NSDictionary *processInfo = [self gtm_processInfoDictionary];
  97. if (processInfo) {
  98. NSNumber *processNumber
  99. = [processInfo objectForKey:kGTMWorkspaceRunningParentPSN];
  100. ProcessSerialNumber parentPSN
  101. = [self gtm_numberToProcessSerialNumber:processNumber];
  102. NSDictionary *parentProcessInfo
  103. = [self gtm_processInfoDictionaryForPSN:&parentPSN];
  104. NSString *parentBundle
  105. = [parentProcessInfo objectForKey:kGTMWorkspaceRunningBundleIdentifier];
  106. wasLaunchedByProcess
  107. = [parentBundle isEqualToString:bundleid];
  108. }
  109. return wasLaunchedByProcess;
  110. }
  111. - (BOOL)gtm_processSerialNumber:(ProcessSerialNumber*)outPSN
  112. withBundleID:(NSString*)bundleID {
  113. if (!outPSN || [bundleID length] == 0) {
  114. return NO;
  115. }
  116. NSArray *apps = [self gtm_launchedApplications];
  117. NSEnumerator *enumerator = [apps objectEnumerator];
  118. NSDictionary *dict;
  119. while ((dict = [enumerator nextObject])) {
  120. NSString *nextID = [dict objectForKey:@"NSApplicationBundleIdentifier"];
  121. if ([nextID isEqualToString:bundleID]) {
  122. NSNumber *psn
  123. = [dict objectForKey:@"NSApplicationProcessSerialNumberLow"];
  124. outPSN->lowLongOfPSN = [psn unsignedIntValue];
  125. psn = [dict objectForKey:@"NSApplicationProcessSerialNumberHigh"];
  126. outPSN->highLongOfPSN = [psn unsignedIntValue];
  127. return YES;
  128. }
  129. }
  130. return NO;
  131. }
  132. - (ProcessSerialNumber)gtm_numberToProcessSerialNumber:(NSNumber*)number {
  133. // There is a bug in Tiger where they were packing ProcessSerialNumbers
  134. // incorrectly into the longlong that they stored in the dictionary.
  135. // This fixes it.
  136. ProcessSerialNumber outPSN = { kNoProcess, kNoProcess};
  137. if (number) {
  138. long long temp = [number longLongValue];
  139. UInt32 hi = (UInt32)((temp >> 32) & 0x00000000FFFFFFFFLL);
  140. UInt32 lo = (UInt32)((temp >> 0) & 0x00000000FFFFFFFFLL);
  141. #if MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_X_VERSION_10_5
  142. outPSN.highLongOfPSN = hi;
  143. outPSN.lowLongOfPSN = lo;
  144. #else // MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
  145. if ([GTMSystemVersion isLeopardOrGreater]) {
  146. outPSN.highLongOfPSN = hi;
  147. outPSN.lowLongOfPSN = lo;
  148. } else {
  149. #if TARGET_RT_BIG_ENDIAN
  150. outPSN.highLongOfPSN = hi;
  151. outPSN.lowLongOfPSN = lo;
  152. #else
  153. outPSN.highLongOfPSN = lo;
  154. outPSN.lowLongOfPSN = hi;
  155. #endif // TARGET_RT_BIG_ENDIAN
  156. }
  157. #endif // MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_4
  158. }
  159. return outPSN;
  160. }
  161. - (NSArray *)gtm_launchedApplications {
  162. GTMWorkspaceRunningApplicationList *list
  163. = [GTMWorkspaceRunningApplicationList sharedApplicationList];
  164. return [list launchedApplications];
  165. }
  166. @end
  167. @implementation GTMWorkspaceRunningApplicationList
  168. + (GTMWorkspaceRunningApplicationList *)sharedApplicationList {
  169. static GTMWorkspaceRunningApplicationList *obj;
  170. if (!obj) {
  171. obj = [[self alloc] init];
  172. }
  173. return obj;
  174. }
  175. - (id)init {
  176. if ((self = [super init])) {
  177. [self didLaunchOrTerminateApp:nil];
  178. }
  179. return self;
  180. }
  181. - (void)finalize {
  182. [self didLaunchOrTerminateApp:nil];
  183. [super finalize];
  184. }
  185. - (void)dealloc {
  186. [self didLaunchOrTerminateApp:nil];
  187. [super dealloc];
  188. }
  189. - (void)didLaunchOrTerminateApp:(NSNotification *)notification {
  190. @synchronized (self) {
  191. [launchedApps_ release];
  192. NSNotificationCenter *workSpaceNC
  193. = [[NSWorkspace sharedWorkspace] notificationCenter];
  194. [workSpaceNC removeObserver:self];
  195. launchedApps_ = nil;
  196. }
  197. }
  198. - (NSArray *)currentApps {
  199. // Not using any NSWorkspace calls because they are not documented as being
  200. // threadsafe.
  201. ProcessSerialNumber psn = { kNoProcess, kNoProcess };
  202. NSMutableArray *launchedApps = [NSMutableArray array];
  203. while (GetNextProcess(&psn) == noErr) {
  204. CFDictionaryRef cfDict
  205. = ProcessInformationCopyDictionary(&psn,
  206. kProcessDictionaryIncludeAllInformationMask);
  207. NSDictionary *carbonDict = GTMCFAutorelease(cfDict);
  208. // Check to make sure we actually have a dictionary. The process could
  209. // have disappeared between the call to GetNextProcess and
  210. // ProcessInformationCopyDictionary.
  211. if (carbonDict) {
  212. NSMutableDictionary *cocoaDict = [NSMutableDictionary dictionary];
  213. NSString *path = [carbonDict objectForKey:@"BundlePath"];
  214. if (path) {
  215. [cocoaDict setObject:path forKey:@"NSApplicationPath"];
  216. }
  217. NSString *name = [carbonDict objectForKey:(id)kCFBundleNameKey];
  218. if (name) {
  219. [cocoaDict setObject:name forKey:@"NSApplicationName"];
  220. }
  221. NSString *bundleID = [carbonDict objectForKey:(id)kCFBundleIdentifierKey];
  222. if (bundleID) {
  223. [cocoaDict setObject:bundleID forKey:@"NSApplicationBundleIdentifier"];
  224. }
  225. NSNumber *pid = [carbonDict objectForKey:@"pid"];
  226. if (pid) {
  227. [cocoaDict setObject:pid forKey:@"NSApplicationProcessIdentifier"];
  228. }
  229. [cocoaDict setObject:[NSNumber numberWithUnsignedLong:psn.highLongOfPSN]
  230. forKey:@"NSApplicationProcessSerialNumberHigh"];
  231. [cocoaDict setObject:[NSNumber numberWithUnsignedLong:psn.lowLongOfPSN]
  232. forKey:@"NSApplicationProcessSerialNumberLow"];
  233. [launchedApps addObject:cocoaDict];
  234. }
  235. }
  236. return launchedApps;
  237. }
  238. - (NSArray *)launchedApplications {
  239. NSArray *localReturn = nil;
  240. @synchronized (self) {
  241. if (!launchedApps_) {
  242. launchedApps_ = [[self currentApps] retain];
  243. NSWorkspace *ws = [NSWorkspace sharedWorkspace];
  244. NSNotificationCenter *workSpaceNC = [ws notificationCenter];
  245. [workSpaceNC addObserver:self
  246. selector:@selector(didLaunchOrTerminateApp:)
  247. name:NSWorkspaceDidLaunchApplicationNotification
  248. object:nil];
  249. [workSpaceNC addObserver:self
  250. selector:@selector(didLaunchOrTerminateApp:)
  251. name:NSWorkspaceDidTerminateApplicationNotification
  252. object:nil];
  253. }
  254. // We want to keep launchedApps_ in the autoreleasepool of this thread
  255. localReturn = [launchedApps_ retain];
  256. }
  257. return [localReturn autorelease];
  258. }
  259. @end