forked from mirror/smcFanControl
2.4 Beta
Initial Commit
This commit is contained in:
144
Classes/FanControl.h
Normal file
144
Classes/FanControl.h
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* FanControl
|
||||
*
|
||||
* Copyright (c) 2006 Hendrik Holtmann
|
||||
*
|
||||
* FanControl.h - MacBook(Pro) FanControl application
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import "NSFileManager+DirectoryLocations.h"
|
||||
#import <smc.h>
|
||||
#import <smcWrapper.h>
|
||||
#import <MachineDefaults.h>
|
||||
|
||||
#import <Power.h>
|
||||
#include <mach/mach_port.h>
|
||||
#include <mach/mach_interface.h>
|
||||
#include <mach/mach_init.h>
|
||||
|
||||
#include <IOKit/pwr_mgt/IOPMLib.h>
|
||||
#include <IOKit/IOMessage.h>
|
||||
|
||||
|
||||
#define kMenuBarHeight 22
|
||||
|
||||
|
||||
@interface FanControl : NSObject
|
||||
|
||||
{
|
||||
IBOutlet id currentSpeed;
|
||||
IBOutlet id currentSpeed1;
|
||||
|
||||
IBOutlet id slider1;
|
||||
IBOutlet id slider2;
|
||||
|
||||
IBOutlet id field1;
|
||||
IBOutlet id field2;
|
||||
|
||||
IBOutlet id mainwindow;
|
||||
|
||||
IBOutlet id tabview;
|
||||
|
||||
IBOutlet id applybutton;
|
||||
|
||||
IBOutlet id programinfo;
|
||||
|
||||
IBOutlet id copyright;
|
||||
|
||||
IBOutlet id syncslider;
|
||||
|
||||
IBOutlet id TemperatureController;
|
||||
|
||||
IBOutlet id levelIndicator;
|
||||
|
||||
IBOutlet id newfavoritewindow;
|
||||
|
||||
IBOutlet id newfavorite_title;
|
||||
|
||||
IBOutlet id autochange;
|
||||
|
||||
|
||||
IBOutlet NSMenu *theMenu;
|
||||
|
||||
IBOutlet id faqWindow;
|
||||
|
||||
IBOutlet id faqText;
|
||||
|
||||
IBOutlet id sliderCell;
|
||||
|
||||
IBOutlet id sync;
|
||||
|
||||
IBOutlet id colorSelector;
|
||||
|
||||
NSStatusItem *statusItem;
|
||||
|
||||
NSMutableArray* s_menus;
|
||||
|
||||
NSTimer *_readTimer;
|
||||
|
||||
Power *pw;
|
||||
|
||||
IBOutlet id FavoritesController;
|
||||
IBOutlet id FanController;
|
||||
IBOutlet id DefaultsController;
|
||||
|
||||
MachineDefaults *mdefaults;
|
||||
NSDictionary *s_sed;
|
||||
|
||||
NSDictionary *undo_dic;
|
||||
|
||||
NSImage *menu_image;
|
||||
NSImage *menu_image_alt;
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
-(void)terminate:(id)sender;
|
||||
|
||||
- (IBAction)paypal:(id)sender;
|
||||
- (IBAction)visitHomepage:(id)sender;
|
||||
|
||||
- (IBAction)closePreferences:(id)sender;
|
||||
- (IBAction)savePreferences:(id)sender;
|
||||
- (IBAction)updateCheck:(id)sender;
|
||||
|
||||
- (void)init_statusitem;
|
||||
|
||||
//new ones, check old later
|
||||
- (IBAction)loginItem:(id)sender;
|
||||
- (IBAction)add_favorite:(id)sender;
|
||||
- (IBAction)close_favorite:(id)sender;
|
||||
- (IBAction)save_favorite:(id)sender;
|
||||
- (IBAction)delete_favorite:(id)sender;
|
||||
- (IBAction)syncSliders:(id)sender;
|
||||
- (void)apply_quickselect:(id)sender;
|
||||
- (void)apply_settings:(id)sender controllerindex:(int)cIndex;
|
||||
+ (void)setRights;
|
||||
- (void) syncBinder:(Boolean)bind;
|
||||
- (IBAction) changeMenu:(id)sender;
|
||||
- (IBAction)menuSelect:(id)sender;
|
||||
@end
|
||||
|
||||
|
||||
@interface NSNumber (NumberAdditions)
|
||||
- (NSString *) tohex;
|
||||
- (NSNumber*) celsius_fahrenheit;
|
||||
|
||||
@end
|
||||
|
||||
721
Classes/FanControl.m
Normal file
721
Classes/FanControl.m
Normal file
@ -0,0 +1,721 @@
|
||||
/*
|
||||
* FanControl
|
||||
*
|
||||
* Copyright (c) 2006 Hendrik Holtmann
|
||||
*
|
||||
* FanControl.m - MacBook(Pro) FanControl application
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
|
||||
#import "FanControl.h"
|
||||
#import "MachineDefaults.h"
|
||||
#import <Security/Authorization.h>
|
||||
#import <Security/AuthorizationDB.h>
|
||||
#import <Security/AuthorizationTags.h>
|
||||
#import <Sparkle/SUUpdater.h>
|
||||
#import "SystemVersion.h"
|
||||
|
||||
@implementation FanControl
|
||||
|
||||
io_connect_t conn;
|
||||
kern_return_t result;
|
||||
SMCVal_t val;
|
||||
NSUserDefaults *defaults;
|
||||
Boolean supported=false;
|
||||
extern char *optarg;
|
||||
SMCVal_t val;
|
||||
OSStatus status;
|
||||
NSDictionary* machine_defaults;
|
||||
NSString *authpw;
|
||||
|
||||
|
||||
|
||||
#pragma mark **Init-Methods**
|
||||
|
||||
+(void) initialize {
|
||||
|
||||
//avoid Zombies when starting external app
|
||||
signal(SIGCHLD, SIG_IGN);
|
||||
|
||||
[FanControl copyMachinesIfNecessary];
|
||||
//check owner and suid rights
|
||||
[FanControl setRights];
|
||||
|
||||
//talk to smc
|
||||
[smcWrapper init];
|
||||
|
||||
//app in foreground for update notifications
|
||||
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
|
||||
|
||||
}
|
||||
|
||||
+(void)copyMachinesIfNecessary
|
||||
{
|
||||
NSString *path = [[[NSFileManager defaultManager] applicationSupportDirectory] stringByAppendingPathComponent:@"Machines.plist"];
|
||||
if (![[NSFileManager defaultManager] fileExistsAtPath:path]) {
|
||||
[[NSFileManager defaultManager] copyItemAtPath:[[NSBundle mainBundle] pathForResource:@"Machines" ofType:@"plist"] toPath:path error:nil];
|
||||
}
|
||||
}
|
||||
|
||||
-(void)upgradeFavorites
|
||||
{
|
||||
//upgrade favorites
|
||||
NSArray *rfavorites = [FavoritesController arrangedObjects];
|
||||
int j;
|
||||
int i;
|
||||
for (i=0;i<[rfavorites count];i++)
|
||||
{
|
||||
BOOL selected = NO;
|
||||
NSArray *fans = [[rfavorites objectAtIndex:i] objectForKey:@"FanData"];
|
||||
for (j=0;j<[fans count];j++) {
|
||||
if ([[[fans objectAtIndex:j] objectForKey:@"menu"] boolValue] == YES ) {
|
||||
selected = YES;
|
||||
}
|
||||
}
|
||||
if (selected==NO) {
|
||||
[[[[rfavorites objectAtIndex:i] objectForKey:@"FanData"] objectAtIndex:0] setObject:[NSNumber numberWithBool:YES] forKey:@"menu"];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
-(void) awakeFromNib {
|
||||
|
||||
s_sed = nil;
|
||||
pw=[[Power alloc] init];
|
||||
[pw setDelegate:self];
|
||||
[pw registerForSleepWakeNotification];
|
||||
[pw registerForPowerChange];
|
||||
|
||||
//load defaults
|
||||
|
||||
[DefaultsController setAppliesImmediately:NO];
|
||||
|
||||
mdefaults=[[MachineDefaults alloc] init:nil];
|
||||
|
||||
s_sed=[mdefaults get_machine_defaults];
|
||||
|
||||
|
||||
NSMutableArray *favorites=[NSMutableArray arrayWithObjects:
|
||||
[NSMutableDictionary dictionaryWithObjectsAndKeys:
|
||||
@"Default", @"Title",
|
||||
[s_sed objectForKey:@"Fans"], @"FanData",nil],nil];
|
||||
NSRange range=[[MachineDefaults computerModel] rangeOfString:@"MacBook"];
|
||||
if (range.length>0) {
|
||||
//for macbooks add a second default
|
||||
MachineDefaults *msdefaults=[[MachineDefaults alloc] init:nil];
|
||||
NSMutableDictionary *sec_fav=[NSMutableDictionary dictionaryWithObjectsAndKeys:@"Higher RPM", @"Title",
|
||||
[[msdefaults get_machine_defaults] objectForKey:@"Fans"], @"FanData",nil];
|
||||
[favorites addObject:sec_fav];
|
||||
int i;
|
||||
for (i=0;i<[[s_sed objectForKey:@"Fans"] count];i++) {
|
||||
int min_value=([[[[s_sed objectForKey:@"Fans"] objectAtIndex:i] valueForKey:@"Minspeed"] intValue])*2;
|
||||
[[[[favorites objectAtIndex:1] objectForKey:@"FanData"] objectAtIndex:i] setObject:[NSNumber numberWithInt:min_value] forKey:@"selspeed"];
|
||||
|
||||
}
|
||||
[msdefaults release];
|
||||
}
|
||||
|
||||
//sync option for Macbook Pro's
|
||||
NSRange range_mbp=[[MachineDefaults computerModel] rangeOfString:@"MacBookPro"];
|
||||
if (range_mbp.length>0) {
|
||||
[sync setHidden:NO];
|
||||
}
|
||||
|
||||
|
||||
NSString *feedURL = nil;
|
||||
if ([SystemVersion isTiger]) {
|
||||
feedURL = @"http://www.eidac.de/smcfancontrol/smcfancontrol_tiger.xml";
|
||||
} else {
|
||||
feedURL = @"http://www.eidac.de/smcfancontrol/smcfancontrol.xml";
|
||||
}
|
||||
|
||||
//load user defaults
|
||||
defaults = [NSUserDefaults standardUserDefaults];
|
||||
[defaults registerDefaults:
|
||||
[NSMutableDictionary dictionaryWithObjectsAndKeys:
|
||||
[NSNumber numberWithInt:0], @"Unit",
|
||||
[NSNumber numberWithInt:0], @"SelDefault",
|
||||
[NSNumber numberWithBool:NO], @"AutoStart",
|
||||
[NSNumber numberWithBool:NO],@"AutomaticChange",
|
||||
[NSNumber numberWithInt:0],@"selbatt",
|
||||
[NSNumber numberWithInt:0],@"selac",
|
||||
[NSNumber numberWithInt:0],@"selload",
|
||||
[NSNumber numberWithInt:0],@"MenuBar",
|
||||
feedURL,@"SUFeedURL",
|
||||
[NSArchiver archivedDataWithRootObject:[NSColor blackColor]],@"MenuColor",
|
||||
favorites,@"Favorites",
|
||||
nil]];
|
||||
|
||||
|
||||
|
||||
|
||||
s_menus=[[NSMutableArray alloc] init];
|
||||
[s_menus autorelease];
|
||||
int i;
|
||||
for(i=0;i<[smcWrapper get_fan_num];i++){
|
||||
NSMenuItem *mitem=[[NSMenuItem alloc] initWithTitle:[NSString stringWithFormat:@"Fan: %d",i] action:NULL keyEquivalent:@""];
|
||||
[mitem setTag:(i+1)*10];
|
||||
[s_menus insertObject:mitem atIndex:i];
|
||||
[mitem release];
|
||||
}
|
||||
|
||||
[FavoritesController bind:@"content"
|
||||
toObject:[NSUserDefaultsController sharedUserDefaultsController]
|
||||
withKeyPath:@"values.Favorites"
|
||||
options:nil];
|
||||
[FavoritesController setEditable:YES];
|
||||
|
||||
// set slider sync - only for MBP
|
||||
for (i=0;i<[[FavoritesController arrangedObjects] count];i++) {
|
||||
if([[[[FavoritesController arrangedObjects] objectAtIndex:i] objectForKey:@"sync"] boolValue]==YES) {
|
||||
[FavoritesController setSelectionIndex:i];
|
||||
[self syncBinder:[[[[FavoritesController arrangedObjects] objectAtIndex:i] objectForKey:@"sync"] boolValue]];
|
||||
}
|
||||
}
|
||||
|
||||
//init statusitem
|
||||
[self init_statusitem];
|
||||
|
||||
|
||||
[programinfo setStringValue: [NSString stringWithFormat:@"%@ %@",[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleName"]
|
||||
,[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleVersion"] ]];
|
||||
//
|
||||
[copyright setStringValue:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"NSHumanReadableCopyright"]];
|
||||
|
||||
|
||||
//power controls only available on portables
|
||||
if (range.length>0) {
|
||||
[autochange setEnabled:true];
|
||||
} else {
|
||||
[autochange setEnabled:false];
|
||||
}
|
||||
[faqText replaceCharactersInRange:NSMakeRange(0,0) withRTF: [NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"F.A.Q" ofType:@"rtf"]]];
|
||||
[self apply_settings:nil controllerindex:[[defaults objectForKey:@"SelDefault"] intValue]];
|
||||
[[[[theMenu itemWithTag:1] submenu] itemAtIndex:[[defaults objectForKey:@"SelDefault"] intValue]] setState:NSOnState];
|
||||
[[sliderCell dataCell] setControlSize:NSSmallControlSize];
|
||||
[self changeMenu:nil];
|
||||
|
||||
//seting toolbar image
|
||||
menu_image=[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"smc" ofType:@"png"]];
|
||||
menu_image_alt=[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"smcover" ofType:@"png"]];
|
||||
|
||||
//release MachineDefaults class first call
|
||||
//add timer for reading to RunLoop
|
||||
_readTimer = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(readFanData:) userInfo:nil repeats:YES];
|
||||
[_readTimer fire];
|
||||
//autoapply settings if valid
|
||||
[self upgradeFavorites];
|
||||
|
||||
//autostart
|
||||
[[NSUserDefaults standardUserDefaults] setValue:[NSNumber numberWithBool:[self isInAutoStart]] forKey:@"AutoStart"];
|
||||
|
||||
}
|
||||
|
||||
|
||||
-(void)init_statusitem{
|
||||
statusItem = [[[NSStatusBar systemStatusBar] statusItemWithLength: NSVariableStatusItemLength] retain];
|
||||
[statusItem setMenu: theMenu];
|
||||
[statusItem setEnabled: YES];
|
||||
[statusItem setHighlightMode:YES];
|
||||
[statusItem setTitle:@"smc..."];
|
||||
int i;
|
||||
for(i=0;i<[s_menus count];i++) {
|
||||
[theMenu insertItem:[s_menus objectAtIndex:i] atIndex:i];
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
#pragma mark **Action-Methods**
|
||||
- (IBAction)loginItem:(id)sender{
|
||||
if ([sender state]==NSOnState) {
|
||||
[self setStartAtLogin:YES];
|
||||
} else {
|
||||
[self setStartAtLogin:NO];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)add_favorite:(id)sender{
|
||||
[[NSApplication sharedApplication] beginSheet:newfavoritewindow
|
||||
modalForWindow: mainwindow
|
||||
modalDelegate: nil
|
||||
didEndSelector: nil
|
||||
contextInfo: nil];
|
||||
}
|
||||
|
||||
- (IBAction)close_favorite:(id)sender{
|
||||
[newfavoritewindow close];
|
||||
[[NSApplication sharedApplication] endSheet:newfavoritewindow];
|
||||
}
|
||||
|
||||
- (IBAction)save_favorite:(id)sender{
|
||||
MachineDefaults *msdefaults=[[MachineDefaults alloc] init:nil];
|
||||
if ([[newfavorite_title stringValue] length]>0) {
|
||||
NSMutableDictionary *toinsert=[[NSMutableDictionary alloc] initWithObjectsAndKeys:[newfavorite_title stringValue],@"Title",[[msdefaults get_machine_defaults] objectForKey:@"Fans"],@"FanData",nil]; //default as template
|
||||
[toinsert setValue:[NSNumber numberWithInt:0] forKey:@"Standard"];
|
||||
[FavoritesController addObject:toinsert];
|
||||
[toinsert release];
|
||||
[newfavoritewindow close];
|
||||
[[NSApplication sharedApplication] endSheet:newfavoritewindow];
|
||||
}
|
||||
[msdefaults release];
|
||||
[self upgradeFavorites];
|
||||
}
|
||||
|
||||
|
||||
-(void) check_deletion:(id)combo{
|
||||
if ([FavoritesController selectionIndex]==[[defaults objectForKey:combo] intValue]) {
|
||||
[defaults setObject:[NSNumber numberWithInt:0] forKey:combo];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)delete_favorite:(id)sender{
|
||||
int pressesButton=NSRunCriticalAlertPanelRelativeToWindow(
|
||||
NSLocalizedString(@"Delete favorite",nil),
|
||||
[NSString stringWithFormat:NSLocalizedString(@"Do you really want to delete the favorite %@?",nil), [ [ [FavoritesController arrangedObjects] objectAtIndex:[FavoritesController selectionIndex]] objectForKey:@"Title"] ],
|
||||
NSLocalizedString(@"No",nil),
|
||||
NSLocalizedString(@"Yes",nil),nil,mainwindow);
|
||||
if (pressesButton==0) {
|
||||
//delete favorite, but resets presets before
|
||||
[self check_deletion:@"selbatt"];
|
||||
[self check_deletion:@"selac"];
|
||||
[self check_deletion:@"selload"];
|
||||
[FavoritesController removeObjects:[FavoritesController selectedObjects]];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
//reads fan data and updates the gui
|
||||
-(void) readFanData:(NSTimer*)timer{
|
||||
|
||||
NSString *temp;
|
||||
NSString *fan;
|
||||
|
||||
|
||||
//on init handling
|
||||
if (s_sed==nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
//populate Menu Items with recent Data
|
||||
int i;
|
||||
for(i=0;i<[smcWrapper get_fan_num];i++){
|
||||
NSString *fandesc=[[[s_sed objectForKey:@"Fans"] objectAtIndex:i] objectForKey:@"Description"];
|
||||
[[theMenu itemWithTag:(i+1)*10] setTitle:[NSString stringWithFormat:@"%@: %@ rpm",fandesc,[[NSNumber numberWithInt:[smcWrapper get_fan_rpm:i]] stringValue]]];
|
||||
}
|
||||
|
||||
|
||||
float c_temp=[smcWrapper get_maintemp];
|
||||
if ([[defaults objectForKey:@"Unit"] intValue]==0) {
|
||||
temp=[NSString stringWithFormat:@"%@%CC",[NSNumber numberWithFloat:c_temp],(unsigned short)0xb0];
|
||||
} else {
|
||||
NSNumberFormatter *ncf=[[[NSNumberFormatter alloc] init] autorelease];
|
||||
[ncf setFormat:@"00;00;-00"];
|
||||
temp=[NSString stringWithFormat:@"%@%CF",[ncf stringForObjectValue:[[NSNumber numberWithFloat:c_temp] celsius_fahrenheit]],(unsigned short)0xb0];
|
||||
}
|
||||
NSNumberFormatter *nc=[[[NSNumberFormatter alloc] init] autorelease];
|
||||
//avoid jumping in menu bar
|
||||
[nc setFormat:@"000;000;-000"];
|
||||
|
||||
int selected = 0;
|
||||
NSArray *fans = [[[FavoritesController arrangedObjects] objectAtIndex:[FavoritesController selectionIndex]] objectForKey:@"FanData"];
|
||||
for (i=0;i<[fans count];i++)
|
||||
{
|
||||
if ([[[fans objectAtIndex:i] objectForKey:@"menu"] boolValue]==YES) {
|
||||
selected = i;
|
||||
}
|
||||
}
|
||||
|
||||
fan=[NSString stringWithFormat:@"%@rpm",[nc stringForObjectValue:[NSNumber numberWithFloat:[smcWrapper get_fan_rpm:selected]]]];
|
||||
|
||||
if ([[defaults objectForKey:@"MenuBar"] intValue]<=1) {
|
||||
NSString *add;
|
||||
int fsize;
|
||||
if ([[defaults objectForKey:@"MenuBar"] intValue]==0) {
|
||||
add=@"\n";
|
||||
fsize=9;
|
||||
[statusItem setLength:53];
|
||||
} else {
|
||||
add=@" ";
|
||||
fsize=11;
|
||||
[statusItem setLength:96];
|
||||
}
|
||||
NSMutableAttributedString *s_status=[[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@%@%@",temp,add,fan]];
|
||||
NSMutableParagraphStyle *paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
|
||||
[paragraphStyle setAlignment:NSLeftTextAlignment];
|
||||
[s_status addAttribute:NSFontAttributeName value:[NSFont fontWithName:@"Lucida Grande" size:fsize] range:NSMakeRange(0,[s_status length])];
|
||||
[s_status addAttribute:NSParagraphStyleAttributeName value:paragraphStyle range:NSMakeRange(0,[s_status length])];
|
||||
[s_status addAttribute:NSForegroundColorAttributeName value:(NSColor*)[NSUnarchiver unarchiveObjectWithData:[defaults objectForKey:@"MenuColor"]] range:NSMakeRange(0,[s_status length])];
|
||||
[statusItem setAttributedTitle:s_status];
|
||||
[statusItem setImage:nil];
|
||||
[statusItem setAlternateImage:nil];
|
||||
[paragraphStyle release];
|
||||
[s_status release];
|
||||
}
|
||||
|
||||
|
||||
if ([[defaults objectForKey:@"MenuBar"] intValue]==2) {
|
||||
[statusItem setLength:26];
|
||||
[statusItem setTitle:nil];
|
||||
[statusItem setToolTip:[NSString stringWithFormat:@"%@\n%@",temp,fan]];
|
||||
[statusItem setImage:menu_image];
|
||||
[statusItem setAlternateImage:menu_image_alt];
|
||||
|
||||
}
|
||||
|
||||
if ([[defaults objectForKey:@"MenuBar"] intValue]==3) {
|
||||
[statusItem setLength:46];
|
||||
NSMutableAttributedString *s_status=[[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@",temp]];
|
||||
[s_status addAttribute:NSFontAttributeName value:[NSFont fontWithName:@"Lucida Grande" size:12] range:NSMakeRange(0,[s_status length])];
|
||||
[s_status addAttribute:NSForegroundColorAttributeName value:(NSColor*)[NSUnarchiver unarchiveObjectWithData:[defaults objectForKey:@"MenuColor"]] range:NSMakeRange(0,[s_status length])];
|
||||
[statusItem setAttributedTitle:s_status];
|
||||
[statusItem setImage:nil];
|
||||
[statusItem setAlternateImage:nil];
|
||||
[s_status release];
|
||||
|
||||
}
|
||||
if ([[defaults objectForKey:@"MenuBar"] intValue]==4) {
|
||||
[statusItem setLength:65];
|
||||
NSMutableAttributedString *s_status=[[NSMutableAttributedString alloc] initWithString:[NSString stringWithFormat:@"%@",fan]];
|
||||
[s_status addAttribute:NSFontAttributeName value:[NSFont fontWithName:@"Lucida Grande" size:12] range:NSMakeRange(0,[s_status length])];
|
||||
[s_status addAttribute:NSForegroundColorAttributeName value:(NSColor*)[NSUnarchiver unarchiveObjectWithData:[defaults objectForKey:@"MenuColor"]] range:NSMakeRange(0,[s_status length])];
|
||||
[statusItem setAttributedTitle:s_status];
|
||||
[statusItem setImage:nil];
|
||||
[statusItem setAlternateImage:nil];
|
||||
[s_status release];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (IBAction)savePreferences:(id)sender{
|
||||
[(NSUserDefaultsController *)DefaultsController save:sender];
|
||||
[defaults setValue:[FavoritesController content] forKey:@"Favorites"];
|
||||
[defaults synchronize];
|
||||
[mainwindow close];
|
||||
[self apply_settings:sender controllerindex:[FavoritesController selectionIndex]];
|
||||
undo_dic=[NSDictionary dictionaryWithDictionary:[defaults dictionaryRepresentation]];
|
||||
}
|
||||
|
||||
|
||||
|
||||
- (IBAction)closePreferences:(id)sender{
|
||||
[mainwindow close];
|
||||
[DefaultsController revert:sender];
|
||||
}
|
||||
|
||||
|
||||
//set the new fan settings
|
||||
|
||||
-(void)apply_settings:(id)sender controllerindex:(int)cIndex{
|
||||
int i;
|
||||
[FanControl setRights];
|
||||
[FavoritesController setSelectionIndex:cIndex];
|
||||
for (i=0;i<[[[[FavoritesController arrangedObjects] objectAtIndex:cIndex] objectForKey:@"FanData"] count];i++) {
|
||||
[smcWrapper setKey_external:[NSString stringWithFormat:@"F%dMn",i] value:[[[[FanController arrangedObjects] objectAtIndex:i] objectForKey:@"selspeed"] tohex]];
|
||||
}
|
||||
NSMenu *submenu = [[[NSMenu alloc] init] autorelease];
|
||||
|
||||
for(i=0;i<[[FavoritesController arrangedObjects] count];i++){
|
||||
NSMenuItem *submenuItem = [[[NSMenuItem alloc] initWithTitle:[[[FavoritesController arrangedObjects] objectAtIndex:i] objectForKey:@"Title"] action:@selector(apply_quickselect:) keyEquivalent:@""] autorelease];
|
||||
[submenuItem setTag:i*100]; //for later manipulation
|
||||
[submenuItem setEnabled:YES];
|
||||
[submenuItem setTarget:self];
|
||||
[submenuItem setRepresentedObject:[[FavoritesController arrangedObjects] objectAtIndex:i]];
|
||||
[submenu addItem:submenuItem];
|
||||
}
|
||||
|
||||
[[theMenu itemWithTag:1] setSubmenu:submenu];
|
||||
for (i=0;i<[[[theMenu itemWithTag:1] submenu] numberOfItems];i++) {
|
||||
[[[[theMenu itemWithTag:1] submenu] itemAtIndex:i] setState:NSOffState];
|
||||
}
|
||||
[[[[theMenu itemWithTag:1] submenu] itemAtIndex:cIndex] setState:NSOnState];
|
||||
[defaults setObject:[NSNumber numberWithInt:cIndex] forKey:@"SelDefault"];
|
||||
//change active setting display
|
||||
[[theMenu itemWithTag:1] setTitle:[NSString stringWithFormat:@"%@: %@",NSLocalizedString(@"Active Setting",nil),[ [ [FavoritesController arrangedObjects] objectAtIndex:[FavoritesController selectionIndex]] objectForKey:@"Title"] ]];
|
||||
}
|
||||
|
||||
|
||||
|
||||
-(void)apply_quickselect:(id)sender{
|
||||
int i;
|
||||
[FanControl setRights];
|
||||
//set all others items to off
|
||||
for (i=0;i<[[[theMenu itemWithTag:1] submenu] numberOfItems];i++) {
|
||||
[[[[theMenu itemWithTag:1] submenu] itemAtIndex:i] setState:NSOffState];
|
||||
}
|
||||
[sender setState:NSOnState];
|
||||
[[theMenu itemWithTag:1] setTitle:[NSString stringWithFormat:@"%@: %@",NSLocalizedString(@"Active Setting",nil),[sender title]]];
|
||||
[self apply_settings:sender controllerindex:[[[theMenu itemWithTag:1] submenu] indexOfItem:sender]];
|
||||
}
|
||||
|
||||
|
||||
-(void)terminate:(id)sender{
|
||||
//get last active selection
|
||||
[defaults synchronize];
|
||||
SMCClose(conn);
|
||||
[_readTimer invalidate];
|
||||
[pw deregisterForSleepWakeNotification];
|
||||
[pw deregisterForPowerChange];
|
||||
[pw release];
|
||||
[menu_image release];
|
||||
[menu_image_alt release];
|
||||
//[mdefaults release];
|
||||
//[statusItem release];
|
||||
//[s_menus release];
|
||||
//[theMenu release];
|
||||
[[NSApplication sharedApplication] terminate:self];
|
||||
}
|
||||
|
||||
|
||||
|
||||
- (IBAction)syncSliders:(id)sender{
|
||||
if ([sender state]) {
|
||||
[self syncBinder:YES];
|
||||
} else {
|
||||
[self syncBinder:NO];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (IBAction) changeMenu:(id)sender{
|
||||
if ([[[[NSUserDefaultsController sharedUserDefaultsController] values] valueForKey:@"MenuBar"] intValue]==2) {
|
||||
[colorSelector setEnabled:NO];
|
||||
} else {
|
||||
[colorSelector setEnabled:YES];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
- (IBAction)menuSelect:(id)sender{
|
||||
//deactivate all other radio buttons
|
||||
int i;
|
||||
for (i=0;i<[[FanController arrangedObjects] count];i++) {
|
||||
if (i!=[sender selectedRow]) {
|
||||
[[[FanController arrangedObjects] objectAtIndex:i] setValue:[NSNumber numberWithBool:NO] forKey:@"menu"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma mark **Helper-Methods**
|
||||
|
||||
//just a helper to bringt update-info-window to the front
|
||||
- (IBAction)updateCheck:(id)sender{
|
||||
[[[SUUpdater alloc] init] checkForUpdates:sender];
|
||||
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
|
||||
}
|
||||
|
||||
- (IBAction)visitHomepage:(id)sender{
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"http://www.eidac.de/products"]];
|
||||
}
|
||||
|
||||
|
||||
- (IBAction)paypal:(id)sender{
|
||||
[[NSWorkspace sharedWorkspace] openURL:[NSURL URLWithString:@"https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=holtmann%40campus%2dvirtuell%2ede&no_shipping=0&no_note=1&tax=0¤cy_code=EUR&bn=PP%2dDonationsBF&charset=UTF%2d8&country=US"]];
|
||||
}
|
||||
|
||||
-(void) syncBinder:(Boolean)bind{
|
||||
//in case plist is corrupt, don't bind
|
||||
if ([[FanController arrangedObjects] count]>1 ) {
|
||||
if (bind==YES) {
|
||||
[[[FanController arrangedObjects] objectAtIndex:1] bind:@"selspeed" toObject:[[FanController arrangedObjects] objectAtIndex:0] withKeyPath:@"selspeed" options:nil];
|
||||
[[[FanController arrangedObjects] objectAtIndex:0] bind:@"selspeed" toObject:[[FanController arrangedObjects] objectAtIndex:1] withKeyPath:@"selspeed" options:nil];
|
||||
} else {
|
||||
[[[FanController arrangedObjects] objectAtIndex:1] unbind:@"selspeed"];
|
||||
[[[FanController arrangedObjects] objectAtIndex:0] unbind:@"selspeed"];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark **Power Watchdog-Methods**
|
||||
|
||||
- (void)systemDidWakeFromSleep:(id)sender{
|
||||
[self apply_settings:nil controllerindex:[[defaults objectForKey:@"SelDefault"] intValue]];
|
||||
}
|
||||
|
||||
|
||||
- (void)powerChangeToBattery:(id)sender{
|
||||
|
||||
if ([[defaults objectForKey:@"AutomaticChange"] boolValue]==YES) {
|
||||
[self apply_settings:nil controllerindex:[[defaults objectForKey:@"selbatt"] intValue]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)powerChangeToAC:(id)sender{
|
||||
if ([[defaults objectForKey:@"AutomaticChange"] boolValue]==YES) {
|
||||
[self apply_settings:nil controllerindex:[[defaults objectForKey:@"selac"] intValue]];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
- (void)powerChangeToACLoading:(id)sender{
|
||||
if ([[defaults objectForKey:@"AutomaticChange"] boolValue]==YES) {
|
||||
[self apply_settings:nil controllerindex:[[defaults objectForKey:@"selload"] intValue]];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Start-at-login control
|
||||
|
||||
- (BOOL)isInAutoStart
|
||||
{
|
||||
BOOL found = NO;
|
||||
LSSharedFileListRef loginItems = LSSharedFileListCreate(kCFAllocatorDefault, kLSSharedFileListSessionLoginItems, /*options*/ NULL);
|
||||
NSString *path = [[NSBundle mainBundle] bundlePath];
|
||||
CFURLRef URLToToggle = (CFURLRef)[NSURL fileURLWithPath:path];
|
||||
LSSharedFileListItemRef existingItem = NULL;
|
||||
|
||||
UInt32 seed = 0U;
|
||||
NSArray *currentLoginItems = [NSMakeCollectable(LSSharedFileListCopySnapshot(loginItems, &seed)) autorelease];
|
||||
|
||||
for (id itemObject in currentLoginItems) {
|
||||
LSSharedFileListItemRef item = (LSSharedFileListItemRef)itemObject;
|
||||
|
||||
UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
|
||||
CFURLRef URL = NULL;
|
||||
OSStatus err = LSSharedFileListItemResolve(item, resolutionFlags, &URL, /*outRef*/ NULL);
|
||||
if (err == noErr) {
|
||||
Boolean foundIt = CFEqual(URL, URLToToggle);
|
||||
CFRelease(URL);
|
||||
|
||||
if (foundIt) {
|
||||
existingItem = item;
|
||||
found = YES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return found;
|
||||
}
|
||||
|
||||
- (void) setStartAtLogin:(BOOL)enabled {
|
||||
|
||||
LSSharedFileListRef loginItems = LSSharedFileListCreate(kCFAllocatorDefault, kLSSharedFileListSessionLoginItems, /*options*/ NULL);
|
||||
|
||||
|
||||
NSString *path = [[NSBundle mainBundle] bundlePath];
|
||||
|
||||
OSStatus status;
|
||||
CFURLRef URLToToggle = (CFURLRef)[NSURL fileURLWithPath:path];
|
||||
LSSharedFileListItemRef existingItem = NULL;
|
||||
|
||||
UInt32 seed = 0U;
|
||||
NSArray *currentLoginItems = [NSMakeCollectable(LSSharedFileListCopySnapshot(loginItems, &seed)) autorelease];
|
||||
|
||||
for (id itemObject in currentLoginItems) {
|
||||
LSSharedFileListItemRef item = (LSSharedFileListItemRef)itemObject;
|
||||
|
||||
UInt32 resolutionFlags = kLSSharedFileListNoUserInteraction | kLSSharedFileListDoNotMountVolumes;
|
||||
CFURLRef URL = NULL;
|
||||
OSStatus err = LSSharedFileListItemResolve(item, resolutionFlags, &URL, /*outRef*/ NULL);
|
||||
if (err == noErr) {
|
||||
Boolean foundIt = CFEqual(URL, URLToToggle);
|
||||
CFRelease(URL);
|
||||
|
||||
if (foundIt) {
|
||||
existingItem = item;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (enabled && (existingItem == NULL)) {
|
||||
NSString *displayName = [[NSFileManager defaultManager] displayNameAtPath:path];
|
||||
IconRef icon = NULL;
|
||||
FSRef ref;
|
||||
Boolean gotRef = CFURLGetFSRef(URLToToggle, &ref);
|
||||
if (gotRef) {
|
||||
status = GetIconRefFromFileInfo(&ref,
|
||||
/*fileNameLength*/ 0, /*fileName*/ NULL,
|
||||
kFSCatInfoNone, /*catalogInfo*/ NULL,
|
||||
kIconServicesNormalUsageFlag,
|
||||
&icon,
|
||||
/*outLabel*/ NULL);
|
||||
if (status != noErr)
|
||||
icon = NULL;
|
||||
}
|
||||
|
||||
LSSharedFileListInsertItemURL(loginItems, kLSSharedFileListItemBeforeFirst, (CFStringRef)displayName, icon, URLToToggle, /*propertiesToSet*/ NULL, /*propertiesToClear*/ NULL);
|
||||
} else if (!enabled && (existingItem != NULL))
|
||||
LSSharedFileListItemRemove(loginItems, existingItem);
|
||||
}
|
||||
|
||||
|
||||
|
||||
#pragma mark **SMC-Binary Owner/Right Check**
|
||||
//call smc binary with sudo rights and apply
|
||||
+(void)setRights{
|
||||
NSString *smcpath = [[NSBundle mainBundle] pathForResource:@"smc" ofType:@""];
|
||||
NSFileManager *fmanage=[NSFileManager defaultManager];
|
||||
NSDictionary *fdic = [fmanage attributesOfItemAtPath:smcpath error:nil];
|
||||
if ([[fdic valueForKey:@"NSFileOwnerAccountName"] isEqualToString:@"root"] && [[fdic valueForKey:@"NSFileGroupOwnerAccountName"] isEqualToString:@"admin"] && ([[fdic valueForKey:@"NSFilePosixPermissions"] intValue]==3437)) {
|
||||
return;
|
||||
}
|
||||
FILE *commPipe;
|
||||
AuthorizationRef authorizationRef;
|
||||
AuthorizationItem gencitem = { "system.privilege.admin", 0, NULL, 0 };
|
||||
AuthorizationRights gencright = { 1, &gencitem };
|
||||
int flags = kAuthorizationFlagExtendRights | kAuthorizationFlagInteractionAllowed;
|
||||
status = AuthorizationCreate(&gencright, kAuthorizationEmptyEnvironment, flags, &authorizationRef);
|
||||
NSString *tool=@"/usr/sbin/chown";
|
||||
NSArray *argsArray = [NSArray arrayWithObjects: @"root:admin",smcpath,nil];
|
||||
int i;
|
||||
char *args[255];
|
||||
for(i = 0;i < [argsArray count];i++){
|
||||
args[i] = (char *)[[argsArray objectAtIndex:i]cString];
|
||||
}
|
||||
args[i] = NULL;
|
||||
status=AuthorizationExecuteWithPrivileges(authorizationRef,[tool UTF8String],0,args,&commPipe);
|
||||
//second call for suid-bit
|
||||
tool=@"/bin/chmod";
|
||||
argsArray = [NSArray arrayWithObjects: @"6555",smcpath,nil];
|
||||
for(i = 0;i < [argsArray count];i++){
|
||||
args[i] = (char *)[[argsArray objectAtIndex:i]cString];
|
||||
}
|
||||
args[i] = NULL;
|
||||
status=AuthorizationExecuteWithPrivileges(authorizationRef,[tool UTF8String],0,args,&commPipe);
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
|
||||
@implementation NSNumber (NumberAdditions)
|
||||
|
||||
- (NSString*) tohex{
|
||||
return [NSString stringWithFormat:@"%0.4x",[self intValue]<<2];
|
||||
}
|
||||
|
||||
|
||||
- (NSNumber*) celsius_fahrenheit{
|
||||
float celsius=[self floatValue];
|
||||
float fahrenheit=(celsius*9)/5+32;
|
||||
return [NSNumber numberWithFloat:fahrenheit];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
|
||||
37
Classes/MachineDefaults.h
Normal file
37
Classes/MachineDefaults.h
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* FanControl
|
||||
*
|
||||
* Copyright (c) 2006 Hendrik Holtmann
|
||||
*
|
||||
* MachineDefaults.m - MacBook(Pro) FanControl application
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <smcWrapper.h>
|
||||
|
||||
|
||||
@interface MachineDefaults : NSObject {
|
||||
NSString *machine;
|
||||
NSArray *supported_machines;
|
||||
Boolean supported;
|
||||
int machine_num;
|
||||
}
|
||||
|
||||
+ (NSString *)computerModel;
|
||||
- (id)init:(NSString*)p_machine;
|
||||
-(NSDictionary*)get_machine_defaults;
|
||||
- (void)dealloc;
|
||||
@end
|
||||
139
Classes/MachineDefaults.m
Normal file
139
Classes/MachineDefaults.m
Normal file
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* FanControl
|
||||
*
|
||||
* Copyright (c) 2006 Hendrik Holtmann
|
||||
*
|
||||
* MachineDefaults.m - MacBook(Pro) FanControl application
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#import "MachineDefaults.h"
|
||||
#import "NSFileManager+DirectoryLocations.h"
|
||||
|
||||
@implementation MachineDefaults
|
||||
|
||||
|
||||
- (id)init:(NSString*)p_machine{
|
||||
machine=[MachineDefaults computerModel];
|
||||
supported_machines=[[NSArray alloc] initWithContentsOfFile:[[[NSFileManager defaultManager] applicationSupportDirectory] stringByAppendingPathComponent:@"Machines.plist"]];
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
-(Boolean)is_supported{
|
||||
int i;
|
||||
supported=NO;
|
||||
for(i=0;i<[supported_machines count];i++) {
|
||||
if ([machine isEqualToString:[[supported_machines objectAtIndex:i] objectForKey:@"Machine"]]) {
|
||||
supported=YES;
|
||||
machine_num=i;
|
||||
}
|
||||
}
|
||||
return supported;
|
||||
}
|
||||
|
||||
|
||||
|
||||
-(NSDictionary*) readfrom_plist{
|
||||
if (!supported) {return nil;}
|
||||
return [supported_machines objectAtIndex:machine_num];
|
||||
}
|
||||
|
||||
|
||||
|
||||
-(NSDictionary*) readfrom_smc{
|
||||
if (supported) {return nil;}
|
||||
int num_fans,i;
|
||||
[smcWrapper init];
|
||||
num_fans=[smcWrapper get_fan_num];
|
||||
NSString *desc;
|
||||
NSNumber *min,*max;
|
||||
NSData *xmldata;
|
||||
NSString *error;
|
||||
NSMutableArray *fans=[[NSMutableArray alloc] init];
|
||||
for (i = 0; i < num_fans; i++) {
|
||||
min=[NSNumber numberWithInt:[smcWrapper get_min_speed:i]];
|
||||
max=[NSNumber numberWithInt:[smcWrapper get_max_speed:i]];
|
||||
desc=[smcWrapper get_fan_descr:i];
|
||||
[fans addObject:[NSDictionary dictionaryWithObjectsAndKeys:desc,@"Description",min,@"Minspeed",max,@"Maxspeed",min,@"selspeed",nil]];
|
||||
}
|
||||
//save to plist for future
|
||||
NSMutableArray *supported_m=[[NSMutableArray alloc] initWithContentsOfFile:[[[NSFileManager defaultManager] applicationSupportDirectory] stringByAppendingPathComponent:@"Machines.plist"]];
|
||||
NSDictionary *new_machine= [NSDictionary dictionaryWithObjectsAndKeys:fans,@"Fans",[NSNumber numberWithInt:num_fans],@"NumFans",machine,@"Machine",@"Autogenerated",@"Comment",nil];
|
||||
[fans release];
|
||||
[supported_m addObject:new_machine];
|
||||
|
||||
//save to plist
|
||||
xmldata = [NSPropertyListSerialization dataFromPropertyList:supported_m
|
||||
format:NSPropertyListXMLFormat_v1_0
|
||||
errorDescription:&error];
|
||||
[xmldata writeToFile:[[[NSFileManager defaultManager] applicationSupportDirectory] stringByAppendingPathComponent:@"Machines.plist"] atomically:YES];
|
||||
[supported_m release];
|
||||
//return new machine-live-data
|
||||
return [new_machine retain];
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
-(NSDictionary*)get_machine_defaults{
|
||||
NSDictionary *m_defaults=nil;
|
||||
if ([self is_supported]) {
|
||||
m_defaults=[self readfrom_plist];
|
||||
int i;
|
||||
//localize fan-descriptions
|
||||
for (i=0;i<[[m_defaults objectForKey:@"Fans"] count];i++) {
|
||||
NSString *newvalue=NSLocalizedString([[[m_defaults objectForKey:@"Fans"] objectAtIndex:i] objectForKey:@"Description"],nil);
|
||||
[[[m_defaults objectForKey:@"Fans"] objectAtIndex:i] setValue:newvalue forKey:@"Description"];
|
||||
}
|
||||
} else {
|
||||
NSAlert *alert = [NSAlert alertWithMessageText:NSLocalizedString(@"Alert!",nil)
|
||||
defaultButton:NSLocalizedString(@"Continue",nil) alternateButton:NSLocalizedString(@"Quit",nil) otherButton:nil
|
||||
informativeTextWithFormat:NSLocalizedString(@"smcFanControl has not been tested on this machine yet, but it should run if you follow the instructions. \n\nIf you choose to continue, please make you have no other FanControl-software running. Otherwise please quit, deinstall the other software, restart your machine and rerun smcFanControl!",nil)];
|
||||
int code=[alert runModal];
|
||||
if (code==NSAlertDefaultReturn) {
|
||||
m_defaults=[self readfrom_smc];
|
||||
} else {
|
||||
[[NSApplication sharedApplication] terminate:nil];
|
||||
}
|
||||
|
||||
}
|
||||
return m_defaults;
|
||||
}
|
||||
|
||||
+ (NSString *)computerModel
|
||||
{
|
||||
static NSString *computerModel = nil;
|
||||
if (!computerModel) {
|
||||
io_service_t pexpdev;
|
||||
if ((pexpdev = IOServiceGetMatchingService (kIOMasterPortDefault, IOServiceMatching("IOPlatformExpertDevice"))))
|
||||
{
|
||||
NSData *data;
|
||||
if ((data = (id)IORegistryEntryCreateCFProperty(pexpdev, CFSTR("model"), kCFAllocatorDefault, 0))) {
|
||||
computerModel = [[NSString allocWithZone:NULL] initWithCString:[data bytes] encoding:NSASCIIStringEncoding];
|
||||
[data release];
|
||||
}
|
||||
}
|
||||
}
|
||||
return computerModel;
|
||||
}
|
||||
|
||||
- (void)dealloc{
|
||||
[super dealloc];
|
||||
//[supported_machines release];
|
||||
}
|
||||
|
||||
@end
|
||||
36
Classes/NSFileManager+DirectoryLocations.h
Normal file
36
Classes/NSFileManager+DirectoryLocations.h
Normal file
@ -0,0 +1,36 @@
|
||||
//
|
||||
// NSFileManager+DirectoryLocations.h
|
||||
//
|
||||
// Created by Matt Gallagher on 06 May 2010
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software. Permission is granted to anyone to
|
||||
// use this software for any purpose, including commercial applications, and to
|
||||
// alter it and redistribute it freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
//
|
||||
// DirectoryLocations is a set of global methods for finding the fixed location
|
||||
// directoriess.
|
||||
//
|
||||
@interface NSFileManager (DirectoryLocations)
|
||||
|
||||
- (NSString *)findOrCreateDirectory:(NSSearchPathDirectory)searchPathDirectory
|
||||
inDomain:(NSSearchPathDomainMask)domainMask
|
||||
appendPathComponent:(NSString *)appendComponent
|
||||
error:(NSError **)errorOut;
|
||||
- (NSString *)applicationSupportDirectory;
|
||||
|
||||
@end
|
||||
155
Classes/NSFileManager+DirectoryLocations.m
Normal file
155
Classes/NSFileManager+DirectoryLocations.m
Normal file
@ -0,0 +1,155 @@
|
||||
//
|
||||
// NSFileManager+DirectoryLocations.m
|
||||
//
|
||||
// Created by Matt Gallagher on 06 May 2010
|
||||
//
|
||||
// This software is provided 'as-is', without any express or implied
|
||||
// warranty. In no event will the authors be held liable for any damages
|
||||
// arising from the use of this software. Permission is granted to anyone to
|
||||
// use this software for any purpose, including commercial applications, and to
|
||||
// alter it and redistribute it freely, subject to the following restrictions:
|
||||
//
|
||||
// 1. The origin of this software must not be misrepresented; you must not
|
||||
// claim that you wrote the original software. If you use this software
|
||||
// in a product, an acknowledgment in the product documentation would be
|
||||
// appreciated but is not required.
|
||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||
// misrepresented as being the original software.
|
||||
// 3. This notice may not be removed or altered from any source
|
||||
// distribution.
|
||||
//
|
||||
|
||||
#import "NSFileManager+DirectoryLocations.h"
|
||||
|
||||
enum
|
||||
{
|
||||
DirectoryLocationErrorNoPathFound,
|
||||
DirectoryLocationErrorFileExistsAtLocation
|
||||
};
|
||||
|
||||
NSString * const DirectoryLocationDomain = @"DirectoryLocationDomain";
|
||||
|
||||
@implementation NSFileManager (DirectoryLocations)
|
||||
|
||||
//
|
||||
// findOrCreateDirectory:inDomain:appendPathComponent:error:
|
||||
//
|
||||
// Method to tie together the steps of:
|
||||
// 1) Locate a standard directory by search path and domain mask
|
||||
// 2) Select the first path in the results
|
||||
// 3) Append a subdirectory to that path
|
||||
// 4) Create the directory and intermediate directories if needed
|
||||
// 5) Handle errors by emitting a proper NSError object
|
||||
//
|
||||
// Parameters:
|
||||
// searchPathDirectory - the search path passed to NSSearchPathForDirectoriesInDomains
|
||||
// domainMask - the domain mask passed to NSSearchPathForDirectoriesInDomains
|
||||
// appendComponent - the subdirectory appended
|
||||
// errorOut - any error from file operations
|
||||
//
|
||||
// returns the path to the directory (if path found and exists), nil otherwise
|
||||
//
|
||||
- (NSString *)findOrCreateDirectory:(NSSearchPathDirectory)searchPathDirectory
|
||||
inDomain:(NSSearchPathDomainMask)domainMask
|
||||
appendPathComponent:(NSString *)appendComponent
|
||||
error:(NSError **)errorOut
|
||||
{
|
||||
//
|
||||
// Search for the path
|
||||
//
|
||||
NSArray* paths = NSSearchPathForDirectoriesInDomains(
|
||||
searchPathDirectory,
|
||||
domainMask,
|
||||
YES);
|
||||
if ([paths count] == 0)
|
||||
{
|
||||
if (errorOut)
|
||||
{
|
||||
NSDictionary *userInfo =
|
||||
[NSDictionary dictionaryWithObjectsAndKeys:
|
||||
NSLocalizedStringFromTable(
|
||||
@"No path found for directory in domain.",
|
||||
@"Errors",
|
||||
nil),
|
||||
NSLocalizedDescriptionKey,
|
||||
[NSNumber numberWithInteger:searchPathDirectory],
|
||||
@"NSSearchPathDirectory",
|
||||
[NSNumber numberWithInteger:domainMask],
|
||||
@"NSSearchPathDomainMask",
|
||||
nil];
|
||||
*errorOut =
|
||||
[NSError
|
||||
errorWithDomain:DirectoryLocationDomain
|
||||
code:DirectoryLocationErrorNoPathFound
|
||||
userInfo:userInfo];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
//
|
||||
// Normally only need the first path returned
|
||||
//
|
||||
NSString *resolvedPath = [paths objectAtIndex:0];
|
||||
|
||||
//
|
||||
// Append the extra path component
|
||||
//
|
||||
if (appendComponent)
|
||||
{
|
||||
resolvedPath = [resolvedPath
|
||||
stringByAppendingPathComponent:appendComponent];
|
||||
}
|
||||
|
||||
//
|
||||
// Create the path if it doesn't exist
|
||||
//
|
||||
NSError *error = nil;
|
||||
BOOL success = [self
|
||||
createDirectoryAtPath:resolvedPath
|
||||
withIntermediateDirectories:YES
|
||||
attributes:nil
|
||||
error:&error];
|
||||
if (!success)
|
||||
{
|
||||
if (errorOut)
|
||||
{
|
||||
*errorOut = error;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
//
|
||||
// If we've made it this far, we have a success
|
||||
//
|
||||
if (errorOut)
|
||||
{
|
||||
*errorOut = nil;
|
||||
}
|
||||
return resolvedPath;
|
||||
}
|
||||
|
||||
//
|
||||
// applicationSupportDirectory
|
||||
//
|
||||
// Returns the path to the applicationSupportDirectory (creating it if it doesn't
|
||||
// exist).
|
||||
//
|
||||
- (NSString *)applicationSupportDirectory
|
||||
{
|
||||
NSString *executableName =
|
||||
[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleExecutable"];
|
||||
NSError *error;
|
||||
NSString *result =
|
||||
[self
|
||||
findOrCreateDirectory:NSApplicationSupportDirectory
|
||||
inDomain:NSUserDomainMask
|
||||
appendPathComponent:executableName
|
||||
error:&error];
|
||||
if (!result)
|
||||
{
|
||||
NSLog(@"Unable to find or create application support directory:\n%@", error);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@end
|
||||
70
Classes/Power.h
Normal file
70
Classes/Power.h
Normal file
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* FanControl
|
||||
*
|
||||
* Copyright (c) 2006 Hendrik Holtmann
|
||||
*
|
||||
* Power.h - MacBook(Pro) FanControl application
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#include <IOKit/IOKitLib.h>
|
||||
#include <IOKit/ps/IOPSKeys.h>
|
||||
#include <IOKit/ps/IOPowerSources.h>
|
||||
#include <IOKit/pwr_mgt/IOPMLib.h>
|
||||
#include <IOKit/IOMessage.h>
|
||||
|
||||
|
||||
@interface Power : NSObject {
|
||||
|
||||
io_connect_t root_port;
|
||||
io_object_t notifier;
|
||||
IONotificationPortRef notificationPort;
|
||||
id _delegate;
|
||||
|
||||
}
|
||||
|
||||
- (id)init;
|
||||
|
||||
- (id)delegate;
|
||||
- (void)setDelegate:(id)new_delegate;
|
||||
|
||||
- (void)registerForSleepWakeNotification;
|
||||
- (void)deregisterForSleepWakeNotification;
|
||||
|
||||
- (void)registerForPowerChange;
|
||||
- (void)deregisterForPowerChange;
|
||||
|
||||
//internal
|
||||
- (void)powerMessageReceived:(natural_t)messageType withArgument:(void *) messageArgument;
|
||||
- (void)powerSourceMesssageReceived:(NSDictionary *)n_description;
|
||||
|
||||
|
||||
@end
|
||||
|
||||
|
||||
//delegate Prototypes
|
||||
@interface NSObject (PowerDelegate)
|
||||
|
||||
- (void)systemDidWakeFromSleep:(id)sender;
|
||||
|
||||
- (void)powerChangeToBattery:(id)sender;
|
||||
|
||||
- (void)powerChangeToAC:(id)sender;
|
||||
|
||||
- (void)powerChangeToACLoading:(id)sender;
|
||||
|
||||
@end
|
||||
177
Classes/Power.m
Normal file
177
Classes/Power.m
Normal file
@ -0,0 +1,177 @@
|
||||
/*
|
||||
* FanControl
|
||||
*
|
||||
* Copyright (c) 2006 Hendrik Holtmann
|
||||
*
|
||||
* Power.m - MacBook(Pro) FanControl application
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#import "Power.h"
|
||||
|
||||
|
||||
static CFRunLoopSourceRef powerNotifierRunLoopSource = NULL;
|
||||
|
||||
static int lastsource=0;
|
||||
|
||||
@implementation Power
|
||||
|
||||
|
||||
void SleepWatcher( void * refCon, io_service_t service, natural_t messageType, void * messageArgument ){
|
||||
[(Power *)refCon powerMessageReceived: messageType withArgument: messageArgument];
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void powerSourceChanged(void * refCon)
|
||||
{
|
||||
CFTypeRef powerBlob = IOPSCopyPowerSourcesInfo();
|
||||
CFArrayRef powerSourcesList = IOPSCopyPowerSourcesList(powerBlob);
|
||||
unsigned count = CFArrayGetCount(powerSourcesList);
|
||||
unsigned int i;
|
||||
for (i = 0U; i < count; ++i) { //in case we have several powersources
|
||||
CFTypeRef powerSource;
|
||||
CFDictionaryRef description;
|
||||
powerSource = CFArrayGetValueAtIndex(powerSourcesList, i);
|
||||
description = IOPSGetPowerSourceDescription(powerBlob, powerSource);
|
||||
//work with NSArray from here
|
||||
NSDictionary *n_description = (NSDictionary *)description;
|
||||
[(Power *)refCon powerSourceMesssageReceived:n_description];
|
||||
}
|
||||
CFRelease(powerBlob);
|
||||
CFRelease(powerSourcesList);
|
||||
}
|
||||
|
||||
- (id)init{
|
||||
[super init];
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
- (void)registerForSleepWakeNotification
|
||||
{
|
||||
root_port = IORegisterForSystemPower(self, ¬ificationPort, SleepWatcher, ¬ifier);
|
||||
CFRunLoopAddSource(CFRunLoopGetCurrent(), IONotificationPortGetRunLoopSource(notificationPort), kCFRunLoopDefaultMode);
|
||||
}
|
||||
|
||||
|
||||
- (void)registerForPowerChange
|
||||
{
|
||||
powerNotifierRunLoopSource = IOPSNotificationCreateRunLoopSource(powerSourceChanged,self);
|
||||
if (powerNotifierRunLoopSource) {
|
||||
CFRunLoopAddSource(CFRunLoopGetCurrent(), powerNotifierRunLoopSource, kCFRunLoopDefaultMode);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)deregisterForSleepWakeNotification
|
||||
{
|
||||
CFRunLoopRemoveSource( CFRunLoopGetCurrent(),
|
||||
IONotificationPortGetRunLoopSource(notificationPort),
|
||||
kCFRunLoopCommonModes );
|
||||
IODeregisterForSystemPower(¬ifier);
|
||||
IOServiceClose(root_port);
|
||||
IONotificationPortDestroy(notificationPort);
|
||||
}
|
||||
|
||||
- (void)deregisterForPowerChange{
|
||||
CFRunLoopRemoveSource(CFRunLoopGetCurrent(), powerNotifierRunLoopSource, kCFRunLoopDefaultMode);
|
||||
CFRelease(powerNotifierRunLoopSource);
|
||||
}
|
||||
|
||||
|
||||
|
||||
- (void)powerMessageReceived:(natural_t)messageType withArgument:(void *) messageArgument
|
||||
{
|
||||
switch (messageType)
|
||||
{
|
||||
case kIOMessageSystemWillSleep:
|
||||
IOAllowPowerChange(root_port, (long)messageArgument);
|
||||
break;
|
||||
case kIOMessageCanSystemSleep:
|
||||
IOAllowPowerChange(root_port, (long)messageArgument);
|
||||
break;
|
||||
case kIOMessageSystemHasPoweredOn:
|
||||
if ([_delegate respondsToSelector:@selector(systemDidWakeFromSleep:)])
|
||||
[_delegate systemDidWakeFromSleep:self];
|
||||
else
|
||||
{
|
||||
[NSException raise:NSInternalInconsistencyException format:@"Delegate doesn't respond to ourDelegate"];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)powerSourceMesssageReceived:(NSDictionary *)n_description{
|
||||
if (([[n_description objectForKey:@"Power Source State"] isEqualToString:@"AC Power"] && [[n_description objectForKey:@"Is Charging"] intValue]==1) && lastsource!=1) {
|
||||
lastsource=1;
|
||||
if ([_delegate respondsToSelector:@selector(powerChangeToACLoading:)])
|
||||
[_delegate powerChangeToACLoading:self];
|
||||
else
|
||||
{
|
||||
[NSException raise:NSInternalInconsistencyException format:@"Delegate doesn't respond to ourDelegate"];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (([[n_description objectForKey:@"Power Source State"] isEqualToString:@"AC Power"] && [[n_description objectForKey:@"Is Charging"] intValue]==0) && lastsource!=2) {
|
||||
lastsource=2;
|
||||
if ([_delegate respondsToSelector:@selector(powerChangeToAC:)])
|
||||
[_delegate powerChangeToAC:self];
|
||||
else
|
||||
{
|
||||
[NSException raise:NSInternalInconsistencyException format:@"Delegate doesn't respond to ourDelegate"];
|
||||
}
|
||||
}
|
||||
|
||||
if (([[n_description objectForKey:@"Power Source State"] isEqualToString:@"Battery Power"]) && lastsource!=3) {
|
||||
lastsource=3;
|
||||
if ([_delegate respondsToSelector:@selector(powerChangeToBattery:)])
|
||||
[_delegate powerChangeToBattery:self];
|
||||
else
|
||||
{
|
||||
[NSException raise:NSInternalInconsistencyException format:@"Delegate doesn't respond to ourDelegate"];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
- (id)delegate
|
||||
{
|
||||
return _delegate;
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id)new_delegate
|
||||
{
|
||||
|
||||
_delegate = new_delegate;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
|
||||
if (_delegate)
|
||||
[nc removeObserver:_delegate name:nil object:self];
|
||||
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
||||
|
||||
@end
|
||||
31
Classes/StatusItemWindow.h
Normal file
31
Classes/StatusItemWindow.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* FanControl
|
||||
*
|
||||
* Copyright (c) 2006 Hendrik Holtmann
|
||||
*
|
||||
* StatusItemWindow.h - MacBook(Pro) FanControl application
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
|
||||
@interface StatusItemWindow : NSWindow {
|
||||
}
|
||||
|
||||
- (void)makeKeyAndOrderFront:(id)sender;
|
||||
|
||||
@end
|
||||
32
Classes/StatusItemWindow.m
Normal file
32
Classes/StatusItemWindow.m
Normal file
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* FanControl
|
||||
*
|
||||
* Copyright (c) 2006 Hendrik Holtmann
|
||||
*
|
||||
* StatusItemWindow.m - MacBook(Pro) FanControl application
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
#import "StatusItemWindow.h"
|
||||
|
||||
|
||||
@implementation StatusItemWindow
|
||||
|
||||
- (void)makeKeyAndOrderFront:(id)sender {
|
||||
[[NSApplication sharedApplication] activateIgnoringOtherApps:YES];
|
||||
[super makeKeyAndOrderFront:sender];
|
||||
}
|
||||
|
||||
@end
|
||||
70
Classes/SystemVersion.h
Normal file
70
Classes/SystemVersion.h
Normal file
@ -0,0 +1,70 @@
|
||||
//
|
||||
// GTMSystemVersion.h
|
||||
//
|
||||
// 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 <Foundation/Foundation.h>
|
||||
|
||||
// A class for getting information about what system we are running on
|
||||
@interface SystemVersion : NSObject
|
||||
|
||||
// Returns the current system version major.minor.bugFix
|
||||
+ (void)getMajor:(SInt32*)major minor:(SInt32*)minor bugFix:(SInt32*)bugFix;
|
||||
|
||||
// Returns the build number of the OS. Useful when looking for bug fixes
|
||||
// in new OSes which all have a set system version.
|
||||
// eg 10.5.5's build number is 9F33. Easy way to check the build number
|
||||
// is to choose "About this Mac" from the Apple menu and click on the version
|
||||
// number.
|
||||
+ (NSString*)build;
|
||||
|
||||
+ (BOOL)isBuildLessThan:(NSString*)build;
|
||||
+ (BOOL)isBuildLessThanOrEqualTo:(NSString*)build;
|
||||
+ (BOOL)isBuildGreaterThan:(NSString*)build;
|
||||
+ (BOOL)isBuildGreaterThanOrEqualTo:(NSString*)build;
|
||||
+ (BOOL)isBuildEqualTo:(NSString *)build;
|
||||
|
||||
// Returns YES if running on 10.3, NO otherwise.
|
||||
+ (BOOL)isPanther;
|
||||
|
||||
// Returns YES if running on 10.4, NO otherwise.
|
||||
+ (BOOL)isTiger;
|
||||
|
||||
// Returns YES if running on 10.5, NO otherwise.
|
||||
+ (BOOL)isLeopard;
|
||||
|
||||
// Returns YES if running on 10.6, NO otherwise.
|
||||
+ (BOOL)isSnowLeopard;
|
||||
|
||||
// Returns a YES/NO if the system is 10.3 or better
|
||||
+ (BOOL)isPantherOrGreater;
|
||||
|
||||
// Returns a YES/NO if the system is 10.4 or better
|
||||
+ (BOOL)isTigerOrGreater;
|
||||
|
||||
// Returns a YES/NO if the system is 10.5 or better
|
||||
+ (BOOL)isLeopardOrGreater;
|
||||
|
||||
// Returns a YES/NO if the system is 10.6 or better
|
||||
+ (BOOL)isSnowLeopardOrGreater;
|
||||
// GTM_MACOS_SDK
|
||||
|
||||
// Returns one of the achitecture strings below. Note that this is the
|
||||
// architecture that we are currently running as, not the hardware architecture.
|
||||
+ (NSString *)runtimeArchitecture;
|
||||
@end
|
||||
|
||||
|
||||
217
Classes/SystemVersion.m
Normal file
217
Classes/SystemVersion.m
Normal file
@ -0,0 +1,217 @@
|
||||
//
|
||||
// GTMSystemVersion.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 "SystemVersion.h"
|
||||
#if GTM_MACOS_SDK
|
||||
#import <CoreServices/CoreServices.h>
|
||||
#endif
|
||||
|
||||
static SInt32 sGTMSystemVersionMajor = 0;
|
||||
static SInt32 sGTMSystemVersionMinor = 0;
|
||||
static SInt32 sGTMSystemVersionBugFix = 0;
|
||||
static NSString *sBuild = nil;
|
||||
|
||||
NSString *const kGTMArch_iPhone = @"iPhone";
|
||||
NSString *const kGTMArch_ppc = @"ppc";
|
||||
NSString *const kGTMArch_ppc64 = @"ppc64";
|
||||
NSString *const kGTMArch_x86_64 = @"x86_64";
|
||||
NSString *const kGTMArch_i386 = @"i386";
|
||||
|
||||
static NSString *const kSystemVersionPlistPath = @"/System/Library/CoreServices/SystemVersion.plist";
|
||||
|
||||
@implementation SystemVersion
|
||||
+ (void)initialize {
|
||||
if (self == [SystemVersion class]) {
|
||||
// Gestalt is the recommended way of getting the OS version (despite a
|
||||
// comment to the contrary in the 10.4 headers and docs; see
|
||||
// <http://lists.apple.com/archives/carbon-dev/2007/Aug/msg00089.html>).
|
||||
// The iPhone doesn't have Gestalt though, so use the plist there.
|
||||
#if GTM_MACOS_SDK
|
||||
require_noerr(Gestalt(gestaltSystemVersionMajor, &sGTMSystemVersionMajor), failedGestalt);
|
||||
require_noerr(Gestalt(gestaltSystemVersionMinor, &sGTMSystemVersionMinor), failedGestalt);
|
||||
require_noerr(Gestalt(gestaltSystemVersionBugFix, &sGTMSystemVersionBugFix), failedGestalt);
|
||||
|
||||
return;
|
||||
|
||||
failedGestalt:
|
||||
;
|
||||
#if MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_3
|
||||
// gestaltSystemVersionMajor et al are only on 10.4 and above, so they
|
||||
// could fail when running on 10.3.
|
||||
SInt32 binaryCodedDec;
|
||||
OSStatus err = err = Gestalt(gestaltSystemVersion, &binaryCodedDec);
|
||||
|
||||
// Note that this code will return x.9.9 for any system rev parts that are
|
||||
// greater than 9 (i.e., 10.10.10 will be 10.9.9). This shouldn't ever be a
|
||||
// problem as the code above takes care of 10.4+.
|
||||
SInt32 msb = (binaryCodedDec & 0x0000F000L) >> 12;
|
||||
msb *= 10;
|
||||
SInt32 lsb = (binaryCodedDec & 0x00000F00L) >> 8;
|
||||
sGTMSystemVersionMajor = msb + lsb;
|
||||
sGTMSystemVersionMinor = (binaryCodedDec & 0x000000F0L) >> 4;
|
||||
sGTMSystemVersionBugFix = (binaryCodedDec & 0x0000000FL);
|
||||
#endif // MAC_OS_X_VERSION_MIN_REQUIRED <= MAC_OS_X_VERSION_10_3
|
||||
|
||||
#else // GTM_MACOS_SDK
|
||||
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
|
||||
NSDictionary *systemVersionPlist
|
||||
= [NSDictionary dictionaryWithContentsOfFile:kSystemVersionPlistPath];
|
||||
NSString *version = [systemVersionPlist objectForKey:@"ProductVersion"];
|
||||
NSArray *versionInfo = [version componentsSeparatedByString:@"."];
|
||||
int length = [versionInfo count];
|
||||
sGTMSystemVersionMajor = [[versionInfo objectAtIndex:0] intValue];
|
||||
sGTMSystemVersionMinor = [[versionInfo objectAtIndex:1] intValue];
|
||||
if (length == 3) {
|
||||
sGTMSystemVersionBugFix = [[versionInfo objectAtIndex:2] intValue];
|
||||
}
|
||||
[pool release];
|
||||
#endif // GTM_MACOS_SDK
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)getMajor:(SInt32*)major minor:(SInt32*)minor bugFix:(SInt32*)bugFix {
|
||||
if (major) {
|
||||
*major = sGTMSystemVersionMajor;
|
||||
}
|
||||
if (minor) {
|
||||
*minor = sGTMSystemVersionMinor;
|
||||
}
|
||||
if (bugFix) {
|
||||
*bugFix = sGTMSystemVersionBugFix;
|
||||
}
|
||||
}
|
||||
|
||||
+ (NSString*)build {
|
||||
@synchronized(self) {
|
||||
// Not cached at initialization time because we don't expect "real"
|
||||
// software to want this, and it costs a bit to get at startup.
|
||||
// This will mainly be for unit test cases.
|
||||
if (!sBuild) {
|
||||
NSDictionary *systemVersionPlist
|
||||
= [NSDictionary dictionaryWithContentsOfFile:kSystemVersionPlistPath];
|
||||
sBuild = [[systemVersionPlist objectForKey:@"ProductBuildVersion"] retain];
|
||||
}
|
||||
}
|
||||
return sBuild;
|
||||
}
|
||||
|
||||
+ (BOOL)isBuildLessThan:(NSString*)build {
|
||||
NSComparisonResult result
|
||||
= [[self build] compare:build
|
||||
options:NSNumericSearch | NSCaseInsensitiveSearch];
|
||||
return result == NSOrderedAscending;
|
||||
}
|
||||
|
||||
+ (BOOL)isBuildLessThanOrEqualTo:(NSString*)build {
|
||||
NSComparisonResult result
|
||||
= [[self build] compare:build
|
||||
options:NSNumericSearch | NSCaseInsensitiveSearch];
|
||||
return result != NSOrderedDescending;
|
||||
}
|
||||
|
||||
+ (BOOL)isBuildGreaterThan:(NSString*)build {
|
||||
NSComparisonResult result
|
||||
= [[self build] compare:build
|
||||
options:NSNumericSearch | NSCaseInsensitiveSearch];
|
||||
return result == NSOrderedDescending;
|
||||
}
|
||||
|
||||
+ (BOOL)isBuildGreaterThanOrEqualTo:(NSString*)build {
|
||||
NSComparisonResult result
|
||||
= [[self build] compare:build
|
||||
options:NSNumericSearch | NSCaseInsensitiveSearch];
|
||||
return result != NSOrderedAscending;
|
||||
}
|
||||
|
||||
+ (BOOL)isBuildEqualTo:(NSString *)build {
|
||||
NSComparisonResult result
|
||||
= [[self build] compare:build
|
||||
options:NSNumericSearch | NSCaseInsensitiveSearch];
|
||||
return result == NSOrderedSame;
|
||||
}
|
||||
|
||||
+ (BOOL)isPanther {
|
||||
return sGTMSystemVersionMajor == 10 && sGTMSystemVersionMinor == 3;
|
||||
}
|
||||
|
||||
+ (BOOL)isTiger {
|
||||
return sGTMSystemVersionMajor == 10 && sGTMSystemVersionMinor == 4;
|
||||
}
|
||||
|
||||
+ (BOOL)isLeopard {
|
||||
return sGTMSystemVersionMajor == 10 && sGTMSystemVersionMinor == 5;
|
||||
}
|
||||
|
||||
+ (BOOL)isSnowLeopard {
|
||||
return sGTMSystemVersionMajor == 10 && sGTMSystemVersionMinor == 6;
|
||||
}
|
||||
|
||||
+ (BOOL)isPantherOrGreater {
|
||||
return (sGTMSystemVersionMajor > 10) ||
|
||||
(sGTMSystemVersionMajor == 10 && sGTMSystemVersionMinor >= 3);
|
||||
}
|
||||
|
||||
+ (BOOL)isTigerOrGreater {
|
||||
return (sGTMSystemVersionMajor > 10) ||
|
||||
(sGTMSystemVersionMajor == 10 && sGTMSystemVersionMinor >= 4);
|
||||
}
|
||||
|
||||
+ (BOOL)isLeopardOrGreater {
|
||||
return (sGTMSystemVersionMajor > 10) ||
|
||||
(sGTMSystemVersionMajor == 10 && sGTMSystemVersionMinor >= 5);
|
||||
}
|
||||
|
||||
+ (BOOL)isSnowLeopardOrGreater {
|
||||
return (sGTMSystemVersionMajor > 10) ||
|
||||
(sGTMSystemVersionMajor == 10 && sGTMSystemVersionMinor >= 6);
|
||||
}
|
||||
|
||||
|
||||
+ (NSString *)runtimeArchitecture {
|
||||
NSString *architecture = nil;
|
||||
#if GTM_IPHONE_SDK
|
||||
architecture = kGTMArch_iPhone;
|
||||
#else // !GTM_IPHONE_SDK
|
||||
// In reading arch(3) you'd thing this would work:
|
||||
//
|
||||
// const NXArchInfo *localInfo = NXGetLocalArchInfo();
|
||||
// _GTMDevAssert(localInfo && localInfo->name, @"Couldn't get NXArchInfo");
|
||||
// const NXArchInfo *genericInfo = NXGetArchInfoFromCpuType(localInfo->cputype, 0);
|
||||
// _GTMDevAssert(genericInfo && genericInfo->name, @"Couldn't get generic NXArchInfo");
|
||||
// extensions[0] = [NSString stringWithFormat:@".%s", genericInfo->name];
|
||||
//
|
||||
// but on 64bit it returns the same things as on 32bit, so...
|
||||
#if __POWERPC__
|
||||
#if __LP64__
|
||||
architecture = kGTMArch_ppc64;
|
||||
#else // !__LP64__
|
||||
architecture = kGTMArch_ppc;
|
||||
#endif // __LP64__
|
||||
#else // !__POWERPC__
|
||||
#if __LP64__
|
||||
architecture = kGTMArch_x86_64;
|
||||
#else // !__LP64__
|
||||
architecture = kGTMArch_i386;
|
||||
#endif // __LP64__
|
||||
#endif // !__POWERPC__
|
||||
|
||||
#endif // GTM_IPHONE_SDK
|
||||
return architecture;
|
||||
}
|
||||
|
||||
@end
|
||||
40
Classes/smcWrapper.h
Normal file
40
Classes/smcWrapper.h
Normal file
@ -0,0 +1,40 @@
|
||||
/*
|
||||
* FanControl
|
||||
*
|
||||
* Copyright (c) 2006 Hendrik Holtmann
|
||||
*
|
||||
* smcWrapper.m - MacBook(Pro) FanControl application
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <openssl/evp.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <smc.h>
|
||||
#import <MachineDefaults.h>
|
||||
|
||||
@interface smcWrapper : NSObject {
|
||||
}
|
||||
|
||||
+(int) get_fan_rpm:(int)fan_number;
|
||||
+(float) get_maintemp;
|
||||
+(float) get_mptemp;
|
||||
+(int) get_fan_num;
|
||||
+(int) get_min_speed:(int)fan_number;
|
||||
+(int) get_max_speed:(int)fan_number;
|
||||
+(void)setKey_external:(NSString *)key value:(NSString *)value;
|
||||
+(NSString*) get_fan_descr:(int)fan_number;
|
||||
|
||||
@end
|
||||
187
Classes/smcWrapper.m
Normal file
187
Classes/smcWrapper.m
Normal file
@ -0,0 +1,187 @@
|
||||
/*
|
||||
* FanControl
|
||||
*
|
||||
* Copyright (c) 2006 Hendrik Holtmann
|
||||
*
|
||||
* smcWrapper.m - MacBook(Pro) FanControl application
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#import "smcWrapper.h"
|
||||
#import <CommonCrypto/CommonDigest.h>
|
||||
|
||||
NSString * const smc_checksum=@"0becdb25cdf64eb74b001c8a77c5e6b7";
|
||||
static NSDictionary *tsensors = nil;
|
||||
|
||||
@implementation smcWrapper
|
||||
io_connect_t conn;
|
||||
|
||||
+(void)init{
|
||||
SMCOpen(&conn);
|
||||
tsensors = [[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"tsensors" ofType:@"plist"]];
|
||||
}
|
||||
|
||||
+(float) get_maintemp{
|
||||
float c_temp;
|
||||
|
||||
NSRange range_pro=[[MachineDefaults computerModel] rangeOfString:@"MacPro"];
|
||||
if (range_pro.length > 0) {
|
||||
//special readout for MacPro
|
||||
c_temp=[smcWrapper get_mptemp];
|
||||
} else {
|
||||
SMCVal_t val;
|
||||
NSMutableArray *allTSensors = [[tsensors allKeys] mutableCopy];
|
||||
NSString *foundKey = [tsensors objectForKey:[MachineDefaults computerModel]];
|
||||
if (foundKey !=nil) {
|
||||
foundKey = [MachineDefaults computerModel];
|
||||
} else {
|
||||
foundKey = @"standard";
|
||||
}
|
||||
[allTSensors removeObject:foundKey];
|
||||
SMCReadKey2((char*)[[tsensors objectForKey:foundKey] UTF8String], &val,conn);
|
||||
c_temp= ((val.bytes[0] * 256 + val.bytes[1]) >> 2)/64;
|
||||
|
||||
if (c_temp<=0) {
|
||||
for (NSString *key in allTSensors) {
|
||||
SMCReadKey2((char*)[[tsensors objectForKey:key] UTF8String], &val,conn);
|
||||
c_temp= ((val.bytes[0] * 256 + val.bytes[1]) >> 2)/64;
|
||||
if (c_temp>0) break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return c_temp;
|
||||
}
|
||||
|
||||
|
||||
//temperature-readout for MacPro contributed by Victor Boyer
|
||||
+(float) get_mptemp{
|
||||
UInt32Char_t keyA;
|
||||
UInt32Char_t keyB;
|
||||
SMCVal_t valA;
|
||||
SMCVal_t valB;
|
||||
// kern_return_t resultA;
|
||||
// kern_return_t resultB;
|
||||
sprintf(keyA, "TCAH");
|
||||
SMCReadKey2(keyA, &valA,conn);
|
||||
sprintf(keyB, "TCBH");
|
||||
SMCReadKey2(keyB, &valB,conn);
|
||||
float c_tempA= ((valA.bytes[0] * 256 + valA.bytes[1]) >> 2)/64.0;
|
||||
float c_tempB= ((valB.bytes[0] * 256 + valB.bytes[1]) >> 2)/64.0;
|
||||
int i_tempA, i_tempB;
|
||||
if (c_tempA < c_tempB)
|
||||
{
|
||||
i_tempB = round(c_tempB);
|
||||
return i_tempB;
|
||||
}
|
||||
else
|
||||
{
|
||||
i_tempA = round(c_tempA);
|
||||
return i_tempA;
|
||||
}
|
||||
}
|
||||
|
||||
+(int) get_fan_rpm:(int)fan_number{
|
||||
UInt32Char_t key;
|
||||
SMCVal_t val;
|
||||
//kern_return_t result;
|
||||
sprintf(key, "F%dAc", fan_number);
|
||||
SMCReadKey2(key, &val,conn);
|
||||
int running= _strtof(val.bytes, val.dataSize, 2);
|
||||
return running;
|
||||
}
|
||||
|
||||
+(int) get_fan_num{
|
||||
// kern_return_t result;
|
||||
SMCVal_t val;
|
||||
int totalFans;
|
||||
SMCReadKey2("FNum", &val,conn);
|
||||
totalFans = _strtoul(val.bytes, val.dataSize, 10);
|
||||
return totalFans;
|
||||
}
|
||||
|
||||
+(NSString*) get_fan_descr:(int)fan_number{
|
||||
UInt32Char_t key;
|
||||
char temp;
|
||||
SMCVal_t val;
|
||||
//kern_return_t result;
|
||||
NSMutableString *desc;
|
||||
// desc=[[NSMutableString alloc] initWithFormat:@"Fan #%d: ",fan_number+1];
|
||||
desc=[[[NSMutableString alloc]init] autorelease];
|
||||
sprintf(key, "F%dID", fan_number);
|
||||
SMCReadKey2(key, &val,conn);
|
||||
int i;
|
||||
for (i = 0; i < val.dataSize; i++) {
|
||||
if ((int)val.bytes[i]>32) {
|
||||
temp=(unsigned char)val.bytes[i];
|
||||
[desc appendFormat:@"%c",temp];
|
||||
}
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
|
||||
+(int) get_min_speed:(int)fan_number{
|
||||
UInt32Char_t key;
|
||||
SMCVal_t val;
|
||||
//kern_return_t result;
|
||||
sprintf(key, "F%dMn", fan_number);
|
||||
SMCReadKey2(key, &val,conn);
|
||||
int min= _strtof(val.bytes, val.dataSize, 2);
|
||||
return min;
|
||||
}
|
||||
|
||||
+(int) get_max_speed:(int)fan_number{
|
||||
UInt32Char_t key;
|
||||
SMCVal_t val;
|
||||
//kern_return_t result;
|
||||
sprintf(key, "F%dMx", fan_number);
|
||||
SMCReadKey2(key, &val,conn);
|
||||
int max= _strtof(val.bytes, val.dataSize, 2);
|
||||
return max;
|
||||
}
|
||||
|
||||
|
||||
+ (NSString*)createCheckSum:(NSString*)path {
|
||||
NSData *d=[NSData dataWithContentsOfMappedFile:path];
|
||||
unsigned char result[CC_MD5_DIGEST_LENGTH];
|
||||
CC_MD5((void *)[d bytes], [d length], result);
|
||||
NSMutableString *ret = [NSMutableString stringWithCapacity:CC_MD5_DIGEST_LENGTH*2];
|
||||
for(int i = 0; i<CC_MD5_DIGEST_LENGTH; i++) {
|
||||
[ret appendFormat:@"%02x",result[i]];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
//call smc binary with setuid rights and apply
|
||||
+(void)setKey_external:(NSString *)key value:(NSString *)value{
|
||||
NSString *launchPath = [[NSBundle mainBundle] pathForResource:@"smc" ofType:@""];
|
||||
//first check if it's the right binary (security)
|
||||
NSString *checksum=[smcWrapper createCheckSum:launchPath];
|
||||
if (![checksum isEqualToString:smc_checksum]) {
|
||||
NSLog(@"smcFanControl: Security Error: smc-binary is not the distributed one");
|
||||
return;
|
||||
}
|
||||
NSArray *argsArray = [NSArray arrayWithObjects: @"-k",key,@"-w",value,nil];
|
||||
NSTask *task;
|
||||
task = [[NSTask alloc] init];
|
||||
[task setLaunchPath: launchPath];
|
||||
[task setArguments: argsArray];
|
||||
[task launch];
|
||||
[task release];
|
||||
}
|
||||
|
||||
@end
|
||||
Reference in New Issue
Block a user