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// Cosmetics setup
195// Setup security for changing boot options
196 AuthorizationItem items = {kAuthorizationRightExecute, 0, NULL, 0};
197 AuthorizationRights rights = {1, &items};
198
199[authView setAuthorizationRights:&rights];
200 authView.delegate = self;
201 [authView updateStatus:nil];
202
203if (!prop->isValid())
204{
205std::string sPath;
206AuthorizationRef auth = [self isUnlocked] ? [[authView authorization] authorizationRef] : NULL;
207CFStringRef errorString=NULL;
208bool cont =true;
209
210id sForcedPath = [mOptionsDict valueForKey: keyForceBootConfigPath];
211const char * szForcedPath = sForcedPath!=nil ? [sForcedPath UTF8String] : NULL;
212if (szForcedPath && *szForcedPath)
213{
214cont = !prop->open(szForcedPath, &errorString, auth);
215}
216else {
217for(int i=0; szBootPaths[i] && cont; i++)
218{
219sPath = szBootPaths[i];
220sPath += szPropFileName;
221cont = !prop->open(sPath.c_str(), &errorString, auth);
222}
223}
224if (cont)
225{
226if(!ft) return;
227ft=false;
228[mStatusText setTextColor: [NSColor redColor] ];
229if (errorString)
230[mStatusText setStringValue:[NSString stringWithFormat: @"Error while parsing com.apple.Boot.plist : %@",
231 errorString] ];
232else
233[mStatusText setStringValue: @"Error while searching for com.apple.Boot.plist"];
234
235}
236else
237{
238[mStatusText setTextColor: [NSColor grayColor] ];
239NSString* ns = [ [NSString alloc] initWithUTF8String:prop->propFilePath() ];
240[mStatusText setStringValue: [NSString stringWithFormat: @"bootConfig: %@", ns] ];
241}
242
243if (prop->isValid())
244{
245// read options in the plist file
246
247partExtractor->hidePartitions(prop->getStringForKey(kHidePartition));
248partExtractor->renamedPartitions(prop->getStringForKey(kRenamePartition));
249
250// partExtractor->resetSwapping();
251id val = [mOptionsDict valueForKey: keySwapHD01];
252[[BootSetupController instance]->mSwapHD01 setIntValue: [val intValue] ];
253[[BootSetupController instance] doSwapHD: [val boolValue] save: false src:0 dst:1];
254
255val = [mOptionsDict valueForKey: keySwapHD02];
256[[BootSetupController instance]->mSwapHD02 setIntValue: [val intValue] ];
257[[BootSetupController instance] doSwapHD: [val boolValue] save: false src:0 dst:2];
258
259// Load all boot Options into the interface components
260[PreferencesControllerBase loadOptionsFromBootFile];
261
262[self selectDefaultPartition];
263}
264
265}
266}
267//--------------------------------------------------------------------------
268- (void) selectDefaultPartition
269{
270 if(!authView) return;
271
272[self refreshLockStates];
273
274// try to get the current default partition if any
275if(partExtractor && prop && prop->isValid())
276{
277const char *sdp = prop->getStringForKey(kDefaultPartition);
278sCurrentDefaultPartition = sdp ? sdp : "";
279if (sCurrentDefaultPartition.size())
280{
281int index = partExtractor->getIndexFromHdStringSpec(sCurrentDefaultPartition.c_str());
282if (index>=0)
283{
284[mPartitionsTable selectRowIndexes:
285 [NSIndexSet indexSetWithIndex:index] byExtendingSelection:NO];
286currentRowSel = index;
287}
288}
289}
290
291}
292
293//--------------------------------------------------------------------------
294// following DieBuch recommendation : using applescript and system events (thanks!):
295- (IBAction)onRestart: (id)sender
296{
297NSInteger n = NSRunAlertPanel(@"Restarting OS X",
298 @"Are you sure you want to restart your computer now ?",
299 @"OK", @"Cancel", nil);
300if (n==1)
301{
302AuthorizationRef auth = [[authView authorization] authorizationRef];
303executePrivilegedCmd(auth,"/usr/bin/osascript","-e 'tell app \"System Events\" to restart'");
304}
305
306}
307//--------------------------------------------------------------------------
308- (IBAction)onShutdown: (id)sender
309{
310NSInteger n = NSRunAlertPanel(@"Shutting Down OS X",
311 @"Are you sure you want to shut down your computer now ?",
312 @"OK", @"Cancel", /*ThirdButtonHere:*/nil
313 /*, args for a printf-style msg go here */);
314if (n==1)
315{
316system("/usr/bin/osascript -e 'tell app \"System Events\" to shut down'");
317}
318}
319
320- (IBAction)onSleep: (id)sender
321{
322system("/usr/bin/osascript -e 'tell app \"System Events\" to sleep'");
323}
324
325//--------------------------------------------------------------------------
326- (void)tableViewSelectionDidChange:(NSNotification *)notification {
327
328NSTableView* tv= mPartitionsTable;
329if ([tv selectedRow] != currentRowSel)
330{
331currentRowSel = [tv selectedRow];
332if (currentRowSel>=0)
333{
334const std::vector<PartitionInfo>& partInfo = partExtractor->partList();
335char hd[7+1]="hd(n,m)";
336hd[3]= ('0'+partInfo[currentRowSel].disk());
337hd[5]= ('0'+partInfo[currentRowSel].partition());
338AuthorizationRef auth= [self isUnlocked] ? [[authView authorization] authorizationRef] : NULL;
339if(prop->setStringForKey(kDefaultPartition, hd))
340 prop->save(auth);
341}
342}
343
344}
345
346//--------------------------------------------------------------------------
347- (NSInteger) numberOfRowsInTableView:(NSTableView *)tableView
348{
349int size = partExtractor ? partExtractor->partList().size() : 0;
350return size;
351}
352
353//--------------------------------------------------------------------------
354- (id)tableView:(NSTableView *)tableView objectValueForTableColumn:(NSTableColumn *)tableColumn row:(NSInteger)row
355{
356id ret=nil;
357
358const std::vector<PartitionInfo>& partInfo = partExtractor->partList();
359
360if (tableColumn == mPartitionImgColumn)
361{
362switch(partInfo[row].imageIndexFromFs())
363{
364case 0:
365ret = mMacOSXImage;
366break;
367case 1:
368ret = mWindowsImage;
369break;
370case 2:
371ret = mLinuxImage;
372break;
373default:
374ret = mUnknownImage;
375break;
376
377}
378}
379else if (tableColumn == mFileSystemColumn)
380{
381ret = [NSString stringWithFormat: @"%s", partInfo[row].cfsType() ];
382}
383else if (tableColumn == mPartitionNameColumn)
384{
385ret = [NSString stringWithFormat: @"%s", partInfo[row].clabel()];
386}
387else if (tableColumn == mPartitionIDColumn)
388{
389ret= [NSString stringWithFormat: @"hd(%d,%d)",
390partInfo[row].disk(),
391partInfo[row].partition()
392];
393}
394
395return ret;
396}
397//--------------------------------------------------------------------------
398
399@end
400

Archive Download this file

Revision: 48