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