1// This file is part of BOINC. 2// http://boinc.berkeley.edu 3// Copyright (C) 2017 University of California 4// 5// BOINC is free software; you can redistribute it and/or modify it 6// under the terms of the GNU Lesser General Public License 7// as published by the Free Software Foundation, 8// either version 3 of the License, or (at your option) any later version. 9// 10// BOINC is distributed in the hope that it will be useful, 11// but WITHOUT ANY WARRANTY; without even the implied warranty of 12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 13// See the GNU Lesser General Public License for more details. 14// 15// You should have received a copy of the GNU Lesser General Public License 16// along with BOINC. If not, see <http://www.gnu.org/licenses/>. 17 18// mac_util.mm 19 20#include "mac_util.h" 21#import <Cocoa/Cocoa.h> 22#define DLOPEN_NO_WARN 23#include <mach-o/dyld.h> 24#include <dlfcn.h> 25 26 27// Returns time in seconds since system was booted 28// 29double getTimeSinceBoot() { 30 return [[NSProcessInfo processInfo] systemUptime]; 31} 32 33 34void getPathToThisApp(char* pathBuf, size_t bufSize) { 35 // Get the app's main bundle 36 NSBundle *main = [NSBundle mainBundle]; 37 NSString *thePath = [main bundlePath]; 38 strlcpy(pathBuf, [thePath UTF8String], bufSize); 39} 40 41 42void BringAppToFront() { 43 [ [NSRunningApplication currentApplication] activateWithOptions:NSApplicationActivateIgnoringOtherApps | NSApplicationActivateAllWindows ]; 44} 45 46 47void BringAppWithPidToFront(pid_t pid) { 48 NSRunningApplication * theRunningApp = [NSRunningApplication runningApplicationWithProcessIdentifier:pid]; 49 if (theRunningApp) { 50 [ theRunningApp activateWithOptions:NSApplicationActivateIgnoringOtherApps | NSApplicationActivateAllWindows ]; 51 } 52} 53 54 55pid_t getActiveAppPid() { 56 NSArray * runningApps = [[NSWorkspace sharedWorkspace] runningApplications]; 57 unsigned int i; 58 unsigned int n = [ runningApps count ]; 59 for (i=0; i<n; i++) { 60 NSRunningApplication * theApp = (NSRunningApplication *)[ runningApps objectAtIndex:i ]; 61 if ([ theApp isActive ]) { 62 return [theApp processIdentifier]; 63 } 64 } 65 return 0; 66} 67 68 69pid_t getPidIfRunning(char * bundleID) { 70 NSString *NSBundleID = [[NSString alloc] initWithUTF8String:bundleID]; 71 NSArray * runningApps = [NSRunningApplication runningApplicationsWithBundleIdentifier:NSBundleID]; 72 if (runningApps) { 73 if ([runningApps count] > 0) { 74 return [((NSRunningApplication *)[runningApps firstObject]) processIdentifier]; 75 } 76 } 77 return 0; 78} 79 80 81// Find the path to the app with the bundle identifier and (optionally) creator code. 82// The creator code can be NULL. 83OSStatus GetPathToAppFromID(OSType creator, CFStringRef bundleID, char *path, size_t maxLen) { 84 CFURLRef appURL = NULL; 85 OSErr err; 86 87 // We must launch the System Events application for the target user 88 err = noErr; 89 *path = '\0'; 90 91 // LSCopyApplicationURLsForBundleIdentifier is not available before OS 10.10 92 CFArrayRef (*LSCopyAppURLsForBundleID)(CFStringRef, CFErrorRef) = NULL; 93 void *LSlib = dlopen("/System/Library/Frameworks/CoreServices.framework/Frameworks/LaunchServices.framework/LaunchServices", RTLD_NOW | RTLD_NODELETE); 94 if (LSlib) { 95 LSCopyAppURLsForBundleID = (CFArrayRef(*)(CFStringRef, CFErrorRef)) dlsym(LSlib, "LSCopyApplicationURLsForBundleIdentifier"); 96 } 97 if (LSCopyAppURLsForBundleID == NULL) { 98 err = fnfErr; 99 } 100 101#if __MAC_OS_X_VERSION_MIN_REQUIRED < 101000 102 if (err != noErr) { // LSCopyAppURLsForBundleID == NULL 103 //LSFindApplicationForInfo is deprecated in OS 10.10, so may not be available in the future 104 OSStatus (*LSFindAppForInfo)(OSType, CFStringRef, CFStringRef, FSRef*, CFURLRef*) = NULL; 105 if (LSlib) { 106 LSFindAppForInfo = (OSStatus(*)(OSType, CFStringRef, CFStringRef, FSRef*, CFURLRef*)) 107 dlsym(LSlib, "LSFindApplicationForInfo"); 108 } 109 if (LSFindAppForInfo == NULL) { 110 if (LSlib) dlclose(LSlib); 111 return fnfErr; 112 } 113 err = (*LSFindAppForInfo)(creator, bundleID, NULL, NULL, &appURL); 114 } else // if (LSCopyApplicationURLsForBundleIdentifier != NULL) 115#endif 116 { 117 if (err == noErr) { 118 CFArrayRef appRefs = (*LSCopyAppURLsForBundleID)(bundleID, NULL); 119 if (appRefs == NULL) { 120 err = fnfErr; 121 } else { 122 appURL = (CFURLRef)CFArrayGetValueAtIndex(appRefs, 0); 123 CFRetain(appURL); 124 CFRelease(appRefs); 125 } 126 } 127 if (err != noErr) { 128 if (LSlib) dlclose(LSlib); 129 return err; 130 } 131 } // end if (LSCopyApplicationURLsForBundleIdentifier != NULL) 132 133 if (err == noErr) { 134 CFStringRef CFPath = CFURLCopyFileSystemPath(appURL, kCFURLPOSIXPathStyle); 135 CFStringGetCString(CFPath, path, maxLen, kCFStringEncodingUTF8); 136 CFRelease(CFPath); 137 } 138 if (appURL) { 139 CFRelease(appURL); 140 } 141 if (LSlib) dlclose(LSlib); 142 return err; 143} 144 145// Test OS version number on all versions of OS X without using deprecated Gestalt 146// compareOSVersionTo(x, y) returns: 147// -1 if the OS version we are running on is less than x.y 148// 0 if the OS version we are running on is equal to x.y 149// +1 if the OS version we are running on is lgreater than x.y 150int compareOSVersionTo(int toMajor, int toMinor) { 151 static SInt32 major = -1; 152 static SInt32 minor = -1; 153 154 if (major < 0) { 155 char vers[100], *p1 = NULL; 156 FILE *f; 157 vers[0] = '\0'; 158 f = popen("sw_vers -productVersion", "r"); 159 if (f) { 160 fscanf(f, "%s", vers); 161 pclose(f); 162 } 163 if (vers[0] == '\0') { 164 fprintf(stderr, "popen(\"sw_vers -productVersion\" failed\n"); 165 fflush(stderr); 166 return 0; 167 } 168 // Extract the major system version number 169 major = atoi(vers); 170 // Extract the minor system version number 171 p1 = strchr(vers, '.'); 172 minor = atoi(p1+1); 173 } 174 175 if (major < toMajor) return -1; 176 if (major > toMajor) return 1; 177 // if (major == toMajor) compare minor version numbers 178 if (minor < toMinor) return -1; 179 if (minor > toMinor) return 1; 180 return 0; 181} 182