Chameleon Applications

Chameleon Applications Svn Source Tree

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

Archive Download this file

Revision: 92