Initial Commit
This commit is contained in:
Hendrik Holtmann
2012-08-20 21:34:54 +02:00
commit 9661b06959
158 changed files with 29484 additions and 0 deletions

144
Classes/FanControl.h Normal file
View 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
View 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&currency_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
View 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
View 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

View 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

View 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
View 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
View 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, &notificationPort, SleepWatcher, &notifier);
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(&notifier);
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

View 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

View 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
View 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
View 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
View 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
View 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