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

Archive Download this file

Revision: 17