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

Archive Download this file

Revision: 12