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

Archive Download this file

Revision: 18