Chameleon Applications

Chameleon Applications Svn Source Tree

Root/trunk/ChameleonPrefPane/Sources/ChameleonPrefPane.mm

1//
2// StartupPrefPanePref.mm
3//
4// Created by Rekursor on 1/16/10.
5//
6
7#import "ChameleonPrefPane.h"
8#import "BootSetupController.h"
9#import "BootFlagsController.h"
10#import "PeripheralsController.h"
11#import "AdvancedSetupController.h"
12
13#include "ShellProcess.h"
14#import "ChameleonPropertyList.h"
15#include <string>
16
17//--------------------------------------------------------------------------
18// Constants
19//--------------------------------------------------------------------------
20static const char * const szBootPaths[]= {
21"/",
22"/Extra/",
23"/Volumes/EFI/Extra/",
24"/Volumes/Cham/Extra/",
25"/Volumes/BootLoaders/Extra/",
26"/Volumes/RX0/Extra/",
27"/Library/Preferences/SystemConfiguration/",
28NULL
29};
30
31static const char* const szPropFileName = "com.apple.Boot.plist";
32
33static const int CurrentPreferencesFileVersion = 0x01; // for future back compatibility
34//--------------------------------------------------------------------------
35// Static file variables
36//--------------------------------------------------------------------------
37static std::string sCurrentDefaultPartition;
38
39PartitionExtractor * partExtractor=NULL;
40
41static int currentRowSel = -1;
42static ChameleonPrefPane *gInstance = NULL;
43
44//--------------------------------------------------------------------------
45
46@implementation ChameleonPrefPane
47
48+ (ChameleonPrefPane *)instance { return(gInstance);}
49
50//--------------------------------------------------------------------------
51- (id) init
52{
53self = [super init];
54gInstance = self;
55
56// set the image to display the current file being played
57mMacOSXImage = [self getImageResource: @"MacOSX" ofType: @"png"];
58mWindowsImage = [self getImageResource: @"Windows" ofType: @"png"];
59mLinuxImage = [self getImageResource: @"Linux" ofType: @"png"];
60mCDROMImage = [self getImageResource: @"CDROM" ofType: @"png"];
61mUnknownImage = [self getImageResource: @"Chameleon" ofType: @"tiff"];
62
63
64 // create the process that will extract the diskutil list infos
65if(!partExtractor) partExtractor = new PartitionExtractor();
66
67// Retrieve the com.chameleon.prefPane.plist config
68return self;
69}
70
71- (NSMutableDictionary*) preferencesFile {return mOptionsDict; }
72- (NSMutableDictionary*) preferencesParts {return mPartitionsDict; }
73- (NSTableView*) partitionsTable { return mPartitionsTable;}
74
75//--------------------------------------------------------------------------
76-(bool) savePreferences: (NSDictionary*) dict
77{
78std::string sPath = [kPreferencesFilePath UTF8String];
79
80if(dict==nil || sPath.length()==0) return false;
81
82AuthorizationRef auth = [self isUnlocked] ? [[authView authorization] authorizationRef] : NULL;
83
84PropertyList::chmodFile(sPath.c_str(), "0777", auth);
85[dict writeToFile:kPreferencesFilePath atomically:YES];
86PropertyList::chmodFile(sPath.c_str(), "0644", auth);
87return true;
88}
89
90//--------------------------------------------------------------------------
91// SFAuthorization implementaion
92//--------------------------------------------------------------------------
93
94// SFAuthorization delegates
95- (void)authorizationViewDidAuthorize:(SFAuthorizationView *)view {
96 [self selectDefaultPartition];
97[self refreshLockStates];
98
99}
100
101//--------------------------------------------------------------------------
102- (void)authorizationViewDidDeauthorize:(SFAuthorizationView *)view {
103 [self refreshLockStates];
104}
105
106//--------------------------------------------------------------------------
107// Setup security for changing boot options
108-(void) initAuthorization
109{
110 AuthorizationItem items = {kAuthorizationRightExecute, 0, NULL, 0};
111 AuthorizationRights rights = {1, &items};
112
113[authView setAuthorizationRights:&rights];
114 authView.delegate = self;
115 [authView updateStatus:nil];
116}
117//--------------------------------------------------------------------------
118- (AuthorizationRef) auth
119{
120return [self isUnlocked] ? [[authView authorization] authorizationRef] : NULL;
121
122}
123
124//--------------------------------------------------------------------------
125- (void) refreshLockStates
126{
127 [mPartitionsTable setEnabled:[self isUnlocked]];
128 [mStatusText setEnabled:[self isUnlocked]];
129
130// Refresh other panels
131[PreferencesControllerBase doForEachGroup: RefreshLockStates withOption: nil];
132}
133
134
135//--------------------------------------------------------------------------
136- (bool)isUnlocked
137{
138 return [authView authorizationState] == SFAuthorizationViewUnlockedState;
139}
140
141//--------------------------------------------------------------------------
142- (id) getImageResource: (NSString *) str ofType: (NSString*) sType
143{
144NSImage * img=nil;
145if(!str) return nil;
146NSBundle * b = [NSBundle bundleForClass:[self class]];
147NSString* sRes = [b pathForResource: str ofType:sType ];
148img = [[NSImage alloc] initWithContentsOfFile: sRes];
149return img;
150}
151
152
153//--------------------------------------------------------------------------
154/** When called here, all outlets references are initialized */
155- (void)awakeFromNib
156{ // called more than once, we only need one resource init
157static bool ft=true;
158if(ft)
159{
160ft=false;
161[selfloadPreferences];
162[self initBootConfig];
163}
164}
165
166//--------------------------------------------------------------------------
167- (void) loadPreferences
168{
169//PrefsProp::instance().open([kPreferencesFilePath UTF8String], CreateIfNotExist,
170// [self auth]);
171
172id oldGlobalPreferences = [ [NSDictionary dictionaryWithContentsOfFile:
173 kPreferencesFilePath ] retain];
174
175mPartitionsDict = [[NSMutableDictionary alloc] init];
176[mPartitionsDict retain];
177
178// Initialize bootConfig desc dict
179[PreferencesControllerBase doForEachGroup: AddOptionsDesc withOption: nil];
180
181if (oldGlobalPreferences!=nil)
182{
183mPreferenceFileVersion= [[oldGlobalPreferences objectForKey: keyPreferencesFileVersion] intValue ];
184[PreferencesControllerBase doForEachGroup: SetDefaultValues withOption: oldGlobalPreferences];
185[PreferencesControllerBase doForEachGroup: LoadPreferencesOptions withOption: oldGlobalPreferences];
186[mPartitionsDict addEntriesFromDictionary: [oldGlobalPreferences objectForKey: keyPartitionsList] ];
187}
188else
189{ // Create a preference plist file with Defaults values
190oldGlobalPreferences = [[NSMutableDictionary alloc] init];
191[PreferencesControllerBase doForEachGroup: SetDefaultValues withOption: oldGlobalPreferences];
192
193// Initialize defaults
194[oldGlobalPreferences setObject: [[NSNumber alloc] initWithInt: CurrentPreferencesFileVersion]
195 forKey: keyPreferencesFileVersion];
196[oldGlobalPreferences setObject: mPartitionsDict forKey: keyPartitionsList];
197
198// Save the preferences file
199[ self savePreferences:oldGlobalPreferences ];
200}
201
202mOptionsDict = [[NSMutableDictionary alloc] init];
203[mOptionsDict addEntriesFromDictionary:oldGlobalPreferences];
204if (mPartitionsDict!=nil) [mPartitionsDict retain];
205[oldGlobalPreferences release];
206}
207
208//--------------------------------------------------------------------------
209- (void) initBootConfig
210{
211static bool ft=true;
212
213[self initAuthorization];
214
215if (!BootProp::instance().isValid())
216{
217std::string sPath;
218CFStringRef errorString=NULL;
219bool cont =true;
220
221id sForcedPath = [mOptionsDict valueForKey: keyForceBootConfigPath];
222const char * szForcedPath = sForcedPath!=nil ? [sForcedPath UTF8String] : NULL;
223if (szForcedPath && *szForcedPath)
224{
225cont = !BootProp::instance().open(szForcedPath, [self auth]);
226}
227else {
228for(int i=0; szBootPaths[i] && cont; i++)
229{
230sPath = szBootPaths[i];
231sPath += szPropFileName;
232cont = !BootProp::instance().open(sPath.c_str(), [self auth]);
233}
234}
235if (cont)
236{
237if(!ft) return;
238ft=false;
239[mStatusText setTextColor: [NSColor redColor] ];
240if (errorString)
241[mStatusText setStringValue:[NSString stringWithFormat: @"Error while parsing com.apple.Boot.plist : %@",
242 errorString] ];
243else
244[mStatusText setStringValue: @"Error while searching for com.apple.Boot.plist"];
245
246}
247else
248{
249[mStatusText setTextColor: [NSColor grayColor] ];
250NSString* ns = [ [NSString alloc] initWithUTF8String:BootProp::instance().propFilePath() ];
251[mStatusText setStringValue: [NSString stringWithFormat: @"bootConfig: %@", ns] ];
252[[BootSetupController instance]->mBootConfigPathText setStringValue:
253[[NSString alloc] initWithUTF8String: BootProp::instance().propFilePath()] ];
254
255}
256
257if (BootProp::instance().isValid())
258{
259// read options in the plist file
260
261partExtractor->hidePartitions(BootProp::instance().getStringForKey(kHidePartition));
262partExtractor->renamedPartitions(BootProp::instance().getStringForKey(kRenamePartition));
263
264// partExtractor->resetSwapping();
265id val = [mOptionsDict valueForKey: keySwapHD01];
266[[BootSetupController instance]->mSwapHD01 setIntValue: [val intValue] ];
267[[BootSetupController instance] doSwapHD: [val boolValue] save: false src:0 dst:1];
268
269val = [mOptionsDict valueForKey: keySwapHD02];
270[[BootSetupController instance]->mSwapHD02 setIntValue: [val intValue] ];
271[[BootSetupController instance] doSwapHD: [val boolValue] save: false src:0 dst:2];
272
273// Load all boot Options into the interface components
274[PreferencesControllerBase loadOptionsFromBootFile];
275[self selectDefaultPartition];
276
277}
278
279}
280}
281//--------------------------------------------------------------------------
282- (void) selectDefaultPartition
283{
284 if(!authView) return;
285
286[self refreshLockStates];
287
288// try to get the current default partition if any
289if(partExtractor && BootProp::instance().isValid())
290{
291const char *sdp = BootProp::instance().getStringForKey(kDefaultPartition);
292sCurrentDefaultPartition = sdp ? sdp : "";
293if (sCurrentDefaultPartition.size())
294{
295int index = partExtractor->getIndexFromHdStringSpec(sCurrentDefaultPartition.c_str());
296if (index>=0)
297{
298[mPartitionsTable selectRowIndexes:
299 [NSIndexSet indexSetWithIndex:index] byExtendingSelection:NO];
300currentRowSel = index;
301}
302}
303}
304
305}
306
307//--------------------------------------------------------------------------
308// following DieBuch recommendation : using applescript and system events (thanks!):
309- (IBAction)onRestart: (id)sender
310{
311NSInteger n = NSRunAlertPanel(@"Restarting OS X",
312 @"Are you sure you want to restart your computer now ?",
313 @"OK", @"Cancel", nil);
314if (n==1)
315{
316AuthorizationRef auth = [[authView authorization] authorizationRef];
317executePrivilegedCmd(auth,"/usr/bin/osascript","-e 'tell app \"System Events\" to restart'");
318}
319
320}
321//--------------------------------------------------------------------------
322- (IBAction)onShutdown: (id)sender
323{
324NSInteger n = NSRunAlertPanel(@"Shutting Down OS X",
325 @"Are you sure you want to shut down your computer now ?",
326 @"OK", @"Cancel", /*ThirdButtonHere:*/nil
327 /*, args for a printf-style msg go here */);
328if (n==1)
329{
330system("/usr/bin/osascript -e 'tell app \"System Events\" to shut down'");
331}
332}
333
334- (IBAction)onSleep: (id)sender
335{
336system("/usr/bin/osascript -e 'tell app \"System Events\" to sleep'");
337}
338
339//--------------------------------------------------------------------------
340- (void)tableViewSelectionDidChange:(NSNotification *)notification {
341
342NSTableView* tv= mPartitionsTable;
343if ([tv selectedRow] != currentRowSel)
344{
345currentRowSel = [tv selectedRow];
346if (currentRowSel>=0)
347{
348const std::vector<PartitionInfo>& partInfo = partExtractor->partList();
349char hd[7+1]="hd(n,m)";
350hd[3]= ('0'+partInfo[currentRowSel].disk());
351hd[5]= ('0'+partInfo[currentRowSel].partition());
352AuthorizationRef auth= [self isUnlocked] ? [[authView authorization] authorizationRef] : NULL;
353if(BootProp::instance().setStringForKey(kDefaultPartition, hd))
354 BootProp::instance().save(auth);
355[ PreferencesControllerBase loadOptionsFromBootFile];
356}
357else
358{ // no line selected
359BootProp::instance().removeKeyAndValue(kDefaultPartition);
360[ PreferencesControllerBase loadOptionsFromBootFile];
361
362}
363}
364
365}
366
367//--------------------------------------------------------------------------
368- (NSInteger) numberOfRowsInTableView:(NSTableView *)tableView
369{
370int size = partExtractor ? partExtractor->partList().size() : 0;
371return size;
372}
373
374//--------------------------------------------------------------------------
375- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
376{
377id ret=nil;
378
379const std::vector<PartitionInfo>& partInfo = partExtractor->partList();
380
381if (tableColumn == mPartitionImgColumn)
382{
383switch(partInfo[row].imageIndexFromFs())
384{
385case 0:
386ret = mMacOSXImage;
387break;
388case 1:
389ret = mWindowsImage;
390break;
391case 2:
392ret = mLinuxImage;
393break;
394default:
395ret = mUnknownImage;
396break;
397
398}
399}
400else if (tableColumn == mFileSystemColumn)
401{
402ret = [NSString stringWithFormat: @"%s", partInfo[row].cfsType() ];
403}
404else if (tableColumn == mPartitionNameColumn)
405{
406ret = [NSString stringWithFormat: @"%s", partInfo[row].clabel()];
407}
408else if (tableColumn == mPartitionIDColumn)
409{
410ret= [NSString stringWithFormat: @"hd(%d,%d)",
411partInfo[row].disk(),
412partInfo[row].partition()
413];
414}
415
416return ret;
417}
418//--------------------------------------------------------------------------
419
420@end
421

Archive Download this file

Revision: 54