Chameleon Applications

Chameleon Applications Svn Source Tree

Root/trunk/ChameleonPrefPane/Sources/ChameleonPrefPane.mm

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

Archive Download this file

Revision: 19