aboutsummaryrefslogtreecommitdiff
path: root/AppKit/GTMNSWorkspace+Running.m
diff options
context:
space:
mode:
Diffstat (limited to 'AppKit/GTMNSWorkspace+Running.m')
-rw-r--r--AppKit/GTMNSWorkspace+Running.m171
1 files changed, 171 insertions, 0 deletions
diff --git a/AppKit/GTMNSWorkspace+Running.m b/AppKit/GTMNSWorkspace+Running.m
new file mode 100644
index 0000000..a031043
--- /dev/null
+++ b/AppKit/GTMNSWorkspace+Running.m
@@ -0,0 +1,171 @@
+//
+// GTMNSWorkspace+Running.m
+//
+// Copyright 2007-2008 Google Inc.
+//
+// Licensed under the Apache License, Version 2.0 (the "License"); you may not
+// use this file except in compliance with the License. You may obtain a copy
+// of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+//
+
+#import "GTMNSWorkspace+Running.h"
+#import <Carbon/Carbon.h>
+#import <unistd.h>
+#import "GTMGarbageCollection.h"
+#import "GTMSystemVersion.h"
+
+NSString *const kGTMWorkspaceRunningPSN = @"PSN";
+NSString *const kGTMWorkspaceRunningFlavor = @"Flavor";
+NSString *const kGTMWorkspaceRunningAttributes = @"Attributes";
+NSString *const kGTMWorkspaceRunningParentPSN = @"ParentPSN";
+NSString *const kGTMWorkspaceRunningFileType = @"FileType";
+NSString *const kGTMWorkspaceRunningFileCreator = @"FileCreator";
+NSString *const kGTMWorkspaceRunningPID = @"pid";
+NSString *const kGTMWorkspaceRunningLSBackgroundOnly = @"LSBackgroundOnly";
+NSString *const kGTMWorkspaceRunningLSUIElement = @"LSUIElement";
+NSString *const kGTMWorkspaceRunningIsHidden = @"IsHiddenAttr";
+NSString *const kGTMWorkspaceRunningCheckedIn = @"IsCheckedInAttr";
+NSString *const kGTMWorkspaceRunningLSUIPresentationMode
+ = @"LSUIPresentationMode";
+NSString *const kGTMWorkspaceRunningBundlePath = @"BundlePath";
+NSString *const kGTMWorkspaceRunningBundleExecutable = @"CFBundleExecutable";
+NSString *const kGTMWorkspaceRunningBundleName = @"CFBundleName";
+NSString *const kGTMWorkspaceRunningBundleIdentifier = @"CFBundleIdentifier";
+NSString *const kGTMWorkspaceRunningBundleVersion = @"CFBundleVersion";
+
+@implementation NSWorkspace (GTMWorkspaceRunningAdditions)
+
+/// Returns a YES/NO if a process w/ the given identifier is running
+- (BOOL)gtm_isAppWithIdentifierRunning:(NSString *)identifier {
+ if ([identifier length] == 0) return NO;
+ NSArray *launchedApps = [self launchedApplications];
+ NSArray *buildIDs
+ = [launchedApps valueForKey:@"NSApplicationBundleIdentifier"];
+ return [buildIDs containsObject:identifier];
+}
+
+- (NSDictionary *)gtm_processInfoDictionaryForPID:(pid_t)pid {
+ NSDictionary *dict = nil;
+ ProcessSerialNumber psn;
+ if (GetProcessForPID(pid, &psn) == noErr) {
+ dict = [self gtm_processInfoDictionaryForPSN:&psn];
+ }
+ return dict;
+}
+
+- (NSDictionary *)gtm_processInfoDictionaryForPSN:(ProcessSerialNumberPtr)psn {
+ NSDictionary *dict = nil;
+ if (psn) {
+ CFDictionaryRef cfDict
+ = ProcessInformationCopyDictionary(psn,
+ kProcessDictionaryIncludeAllInformationMask);
+ dict = GTMCFAutorelease(cfDict);
+ }
+ return dict;
+}
+
+- (NSDictionary *)gtm_processInfoDictionary {
+ NSDictionary *dict = nil;
+ ProcessSerialNumber selfNumber;
+ if (MacGetCurrentProcess(&selfNumber) == noErr) {
+ dict = [self gtm_processInfoDictionaryForPSN:&selfNumber];
+ }
+ return dict;
+}
+
+- (NSDictionary *)gtm_processInfoDictionaryForActiveApp {
+ NSDictionary *processDict = nil;
+ ProcessSerialNumber psn;
+ OSStatus status = GetFrontProcess(&psn);
+ if (status == noErr) {
+ processDict = [self gtm_processInfoDictionaryForPSN:&psn];
+ }
+ return processDict;
+}
+
+- (BOOL)gtm_wasLaunchedAsLoginItem {
+ // If the launching process was 'loginwindow', we were launched as a login
+ // item
+ return [self gtm_wasLaunchedByProcess:@"com.apple.loginwindow"];
+}
+
+- (BOOL)gtm_wasLaunchedByProcess:(NSString*)bundleid {
+ BOOL wasLaunchedByProcess = NO;
+ NSDictionary *processInfo = [self gtm_processInfoDictionary];
+ if (processInfo) {
+ NSNumber *processNumber
+ = [processInfo objectForKey:kGTMWorkspaceRunningParentPSN];
+ ProcessSerialNumber parentPSN
+ = [self gtm_numberToProcessSerialNumber:processNumber];
+ NSDictionary *parentProcessInfo
+ = [self gtm_processInfoDictionaryForPSN:&parentPSN];
+ NSString *parentBundle
+ = [parentProcessInfo objectForKey:kGTMWorkspaceRunningBundleIdentifier];
+ wasLaunchedByProcess
+ = [parentBundle isEqualToString:bundleid];
+ }
+ return wasLaunchedByProcess;
+}
+
+- (BOOL)gtm_processSerialNumber:(ProcessSerialNumber*)outPSN
+ withBundleID:(NSString*)bundleID {
+ if (!outPSN || [bundleID length] == 0) {
+ return NO;
+ }
+
+ NSArray *apps = [self launchedApplications];
+
+ NSEnumerator *enumerator = [apps objectEnumerator];
+ NSDictionary *dict;
+
+ while ((dict = [enumerator nextObject])) {
+ NSString *nextID = [dict objectForKey:@"NSApplicationBundleIdentifier"];
+
+ if ([nextID isEqualToString:bundleID]) {
+ NSNumber *psn
+ = [dict objectForKey:@"NSApplicationProcessSerialNumberLow"];
+ outPSN->lowLongOfPSN = [psn unsignedIntValue];
+
+ psn = [dict objectForKey:@"NSApplicationProcessSerialNumberHigh"];
+ outPSN->highLongOfPSN = [psn unsignedIntValue];
+
+ return YES;
+ }
+ }
+
+ return NO;
+}
+
+- (ProcessSerialNumber)gtm_numberToProcessSerialNumber:(NSNumber*)number {
+ // There is a bug in Tiger where they were packing ProcessSerialNumbers
+ // incorrectly into the longlong that they stored in the dictionary.
+ // This fixes it.
+ ProcessSerialNumber outPSN = { kNoProcess, kNoProcess};
+ if (number) {
+ long long temp = [number longLongValue];
+ UInt32 hi = (UInt32)((temp >> 32) & 0x00000000FFFFFFFFLL);
+ UInt32 lo = (UInt32)((temp >> 0) & 0x00000000FFFFFFFFLL);
+ if ([GTMSystemVersion isLeopardOrGreater]) {
+ outPSN.highLongOfPSN = hi;
+ outPSN.lowLongOfPSN = lo;
+ } else {
+#if TARGET_RT_BIG_ENDIAN
+ outPSN.highLongOfPSN = hi;
+ outPSN.lowLongOfPSN = lo;
+#else
+ outPSN.highLongOfPSN = lo;
+ outPSN.lowLongOfPSN = hi;
+#endif
+ }
+ }
+ return outPSN;
+}
+@end