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

Archive Download this file

Revision: 50