]>
Commit | Line | Data |
---|---|---|
224d48e3 | 1 | /* WinterBoard - Theme Manager for the iPhone |
900dc9a5 | 2 | * Copyright (C) 2008-2014 Jay Freeman (saurik) |
224d48e3 JF |
3 | */ |
4 | ||
900dc9a5 | 5 | /* GNU Lesser General Public License, Version 3 {{{ */ |
224d48e3 | 6 | /* |
900dc9a5 JF |
7 | * WinterBoard is free software: you can redistribute it and/or modify it under |
8 | * the terms of the GNU Lesser General Public License as published by the | |
9 | * Free Software Foundation, either version 3 of the License, or (at your | |
10 | * option) any later version. | |
224d48e3 | 11 | * |
900dc9a5 JF |
12 | * WinterBoard is distributed in the hope that it will be useful, but WITHOUT |
13 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or | |
14 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public | |
15 | * License for more details. | |
224d48e3 | 16 | * |
900dc9a5 JF |
17 | * You should have received a copy of the GNU Lesser General Public License |
18 | * along with WinterBoard. If not, see <http://www.gnu.org/licenses/>. | |
19 | **/ | |
20 | /* }}} */ | |
224d48e3 JF |
21 | |
22 | #import <Foundation/Foundation.h> | |
23 | #import <UIKit/UIKit.h> | |
b39b993d DH |
24 | #import <Preferences/PSRootController.h> |
25 | #import <Preferences/PSViewController.h> | |
224d48e3 JF |
26 | #import <Preferences/PSListController.h> |
27 | #import <Preferences/PSSpecifier.h> | |
28 | #import <Preferences/PSTableCell.h> | |
29 | #import <UIKit/UINavigationButton.h> | |
30 | ||
7c88a3f1 | 31 | #include <dlfcn.h> |
b39b993d | 32 | #include <objc/runtime.h> |
7c88a3f1 | 33 | |
e0c66475 | 34 | static void *libhide; |
7c88a3f1 JF |
35 | static BOOL (*IsIconHiddenDisplayId)(NSString *); |
36 | static BOOL (*HideIconViaDisplayId)(NSString *); | |
37 | static BOOL (*UnHideIconViaDisplayId)(NSString *); | |
38 | ||
fdac1738 | 39 | static NSString *WinterBoardDisplayID = @"com.saurik.WinterBoard"; |
7c88a3f1 | 40 | |
224d48e3 JF |
41 | extern NSString *PSTableCellKey; |
42 | extern "C" UIImage *_UIImageWithName(NSString *); | |
43 | ||
44 | static UIImage *checkImage; | |
45 | static UIImage *uncheckedImage; | |
46 | ||
47 | static BOOL settingsChanged; | |
48 | static NSMutableDictionary *_settings; | |
49 | static NSString *_plist; | |
50 | ||
265e19b2 JF |
51 | /* [NSObject yieldToSelector:(withObject:)] {{{*/ |
52 | @interface NSObject (wb$yieldToSelector) | |
53 | - (id) wb$yieldToSelector:(SEL)selector withObject:(id)object; | |
54 | - (id) wb$yieldToSelector:(SEL)selector; | |
55 | @end | |
56 | ||
57 | @implementation NSObject (Cydia) | |
58 | ||
59 | - (void) wb$doNothing { | |
60 | } | |
61 | ||
62 | - (void) wb$_yieldToContext:(NSMutableArray *)context { | |
63 | NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]); | |
64 | ||
65 | SEL selector(reinterpret_cast<SEL>([[context objectAtIndex:0] pointerValue])); | |
66 | id object([[context objectAtIndex:1] nonretainedObjectValue]); | |
67 | volatile bool &stopped(*reinterpret_cast<bool *>([[context objectAtIndex:2] pointerValue])); | |
68 | ||
69 | /* XXX: deal with exceptions */ | |
70 | id value([self performSelector:selector withObject:object]); | |
71 | ||
72 | NSMethodSignature *signature([self methodSignatureForSelector:selector]); | |
73 | [context removeAllObjects]; | |
74 | if ([signature methodReturnLength] != 0 && value != nil) | |
75 | [context addObject:value]; | |
76 | ||
77 | stopped = true; | |
78 | ||
79 | [self | |
80 | performSelectorOnMainThread:@selector(wb$doNothing) | |
81 | withObject:nil | |
82 | waitUntilDone:NO | |
83 | ]; | |
84 | ||
85 | [pool release]; | |
86 | } | |
87 | ||
88 | - (id) wb$yieldToSelector:(SEL)selector withObject:(id)object { | |
89 | /*return [self performSelector:selector withObject:object];*/ | |
90 | ||
91 | volatile bool stopped(false); | |
92 | ||
93 | NSMutableArray *context([NSMutableArray arrayWithObjects: | |
94 | [NSValue valueWithPointer:selector], | |
95 | [NSValue valueWithNonretainedObject:object], | |
96 | [NSValue valueWithPointer:const_cast<bool *>(&stopped)], | |
97 | nil]); | |
98 | ||
99 | NSThread *thread([[[NSThread alloc] | |
100 | initWithTarget:self | |
101 | selector:@selector(wb$_yieldToContext:) | |
102 | object:context | |
103 | ] autorelease]); | |
104 | ||
105 | [thread start]; | |
106 | ||
107 | NSRunLoop *loop([NSRunLoop currentRunLoop]); | |
108 | NSDate *future([NSDate distantFuture]); | |
109 | ||
110 | while (!stopped && [loop runMode:NSDefaultRunLoopMode beforeDate:future]); | |
111 | ||
112 | return [context count] == 0 ? nil : [context objectAtIndex:0]; | |
113 | } | |
114 | ||
115 | - (id) wb$yieldToSelector:(SEL)selector { | |
116 | return [self wb$yieldToSelector:selector withObject:nil]; | |
117 | } | |
118 | ||
119 | @end | |
120 | /* }}} */ | |
121 | ||
224d48e3 JF |
122 | /* Theme Settings Controller {{{ */ |
123 | @interface WBSThemesController: PSViewController <UITableViewDelegate, UITableViewDataSource> { | |
124 | UITableView *_tableView; | |
125 | NSMutableArray *_themes; | |
126 | } | |
127 | ||
128 | @property (nonatomic, retain) NSMutableArray *themes; | |
129 | ||
130 | + (void) load; | |
131 | ||
132 | - (id) initForContentSize:(CGSize)size; | |
133 | - (id) view; | |
134 | - (id) navigationTitle; | |
135 | - (void) themesChanged; | |
136 | ||
137 | - (int) numberOfSectionsInTableView:(UITableView *)tableView; | |
138 | - (id) tableView:(UITableView *)tableView titleForHeaderInSection:(int)section; | |
139 | - (int) tableView:(UITableView *)tableView numberOfRowsInSection:(int)section; | |
140 | - (id) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; | |
141 | - (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath; | |
142 | - (void) tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath; | |
143 | - (UITableViewCellEditingStyle) tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath; | |
144 | - (BOOL) tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath; | |
145 | - (BOOL) tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath; | |
7c88a3f1 | 146 | |
224d48e3 JF |
147 | @end |
148 | ||
149 | @implementation WBSThemesController | |
150 | ||
151 | @synthesize themes = _themes; | |
152 | ||
153 | + (void) load { | |
154 | NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]); | |
155 | checkImage = [_UIImageWithName(@"UIPreferencesBlueCheck.png") retain]; | |
156 | uncheckedImage = [[UIImage imageWithContentsOfFile:@"/System/Library/PreferenceBundles/WinterBoardSettings.bundle/SearchResultsCheckmarkClear.png"] retain]; | |
157 | [pool release]; | |
158 | } | |
159 | ||
160 | - (id) initForContentSize:(CGSize)size { | |
161 | if ((self = [super initForContentSize:size]) != nil) { | |
162 | self.themes = [_settings objectForKey:@"Themes"]; | |
163 | if (!_themes) { | |
164 | if (NSString *theme = [_settings objectForKey:@"Theme"]) { | |
165 | self.themes = [NSMutableArray arrayWithObject: | |
166 | [NSMutableDictionary dictionaryWithObjectsAndKeys: | |
167 | theme, @"Name", | |
168 | [NSNumber numberWithBool:YES], @"Active", nil]]; | |
169 | [_settings removeObjectForKey:@"Theme"]; | |
170 | } | |
171 | if (!_themes) | |
172 | self.themes = [NSMutableArray array]; | |
173 | [_settings setObject:_themes forKey:@"Themes"]; | |
174 | } | |
175 | ||
176 | NSMutableArray *themesOnDisk([NSMutableArray array]); | |
177 | ||
178 | [themesOnDisk | |
179 | addObjectsFromArray:[[NSFileManager defaultManager] | |
180 | contentsOfDirectoryAtPath:@"/Library/Themes" error:NULL] | |
181 | ]; | |
182 | ||
183 | [themesOnDisk addObjectsFromArray:[[NSFileManager defaultManager] | |
184 | contentsOfDirectoryAtPath:[NSString stringWithFormat:@"%@/Library/SummerBoard/Themes", NSHomeDirectory()] | |
185 | error:NULL | |
186 | ]]; | |
187 | ||
188 | for (int i = 0, count = [themesOnDisk count]; i < count; i++) { | |
189 | NSString *theme = [themesOnDisk objectAtIndex:i]; | |
190 | if ([theme hasSuffix:@".theme"]) | |
191 | [themesOnDisk replaceObjectAtIndex:i withObject:[theme stringByDeletingPathExtension]]; | |
192 | } | |
193 | ||
194 | NSMutableSet *themesSet([NSMutableSet set]); | |
195 | ||
196 | for (int i = 0, count = [_themes count]; i < count; i++) { | |
197 | NSDictionary *theme([_themes objectAtIndex:i]); | |
198 | NSString *name([theme objectForKey:@"Name"]); | |
199 | ||
200 | if (!name || ![themesOnDisk containsObject:name]) { | |
201 | [_themes removeObjectAtIndex:i]; | |
202 | i--; | |
203 | count--; | |
204 | } else { | |
205 | [themesSet addObject:name]; | |
206 | } | |
207 | } | |
208 | ||
209 | for (NSString *theme in themesOnDisk) { | |
210 | if ([themesSet containsObject:theme]) | |
211 | continue; | |
212 | [themesSet addObject:theme]; | |
213 | ||
214 | [_themes insertObject:[NSMutableDictionary dictionaryWithObjectsAndKeys: | |
215 | theme, @"Name", | |
216 | [NSNumber numberWithBool:NO], @"Active", | |
217 | nil] atIndex:0]; | |
218 | } | |
219 | ||
220 | _tableView = [[UITableView alloc] initWithFrame:CGRectMake(0, 0, 320, 480-64) style:UITableViewStyleGrouped]; | |
221 | [_tableView setDataSource:self]; | |
222 | [_tableView setDelegate:self]; | |
223 | [_tableView setEditing:YES]; | |
224 | [_tableView setAllowsSelectionDuringEditing:YES]; | |
b39b993d DH |
225 | if ([self respondsToSelector:@selector(setView:)]) |
226 | [self setView:_tableView]; | |
224d48e3 JF |
227 | } |
228 | return self; | |
229 | } | |
230 | ||
231 | - (void) dealloc { | |
232 | [_tableView release]; | |
233 | [_themes release]; | |
234 | [super dealloc]; | |
235 | } | |
236 | ||
237 | - (id) navigationTitle { | |
238 | return @"Themes"; | |
239 | } | |
240 | ||
241 | - (id) view { | |
242 | return _tableView; | |
243 | } | |
244 | ||
245 | - (void) themesChanged { | |
246 | settingsChanged = YES; | |
247 | } | |
248 | ||
249 | /* UITableViewDelegate / UITableViewDataSource Methods {{{ */ | |
250 | - (int) numberOfSectionsInTableView:(UITableView *)tableView { | |
251 | return 1; | |
252 | } | |
253 | ||
254 | - (id) tableView:(UITableView *)tableView titleForHeaderInSection:(int)section { | |
255 | return nil; | |
256 | } | |
257 | ||
258 | - (int) tableView:(UITableView *)tableView numberOfRowsInSection:(int)section { | |
259 | return _themes.count; | |
260 | } | |
261 | ||
262 | - (id) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { | |
263 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"ThemeCell"]; | |
264 | if (!cell) { | |
265 | cell = [[[UITableViewCell alloc] initWithFrame:CGRectMake(0, 0, 100, 100) reuseIdentifier:@"ThemeCell"] autorelease]; | |
266 | //[cell setTableViewStyle:UITableViewCellStyleDefault]; | |
267 | } | |
268 | ||
269 | NSDictionary *theme([_themes objectAtIndex:indexPath.row]); | |
270 | cell.text = [theme objectForKey:@"Name"]; | |
271 | cell.hidesAccessoryWhenEditing = NO; | |
272 | NSNumber *active([theme objectForKey:@"Active"]); | |
273 | BOOL inactive(active == nil || ![active boolValue]); | |
274 | [cell setImage:(inactive ? uncheckedImage : checkImage)]; | |
275 | return cell; | |
276 | } | |
277 | ||
278 | - (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { | |
279 | UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; | |
280 | NSMutableDictionary *theme = [_themes objectAtIndex:indexPath.row]; | |
281 | NSNumber *active = [theme objectForKey:@"Active"]; | |
282 | BOOL inactive = active == nil || ![active boolValue]; | |
283 | [theme setObject:[NSNumber numberWithBool:inactive] forKey:@"Active"]; | |
284 | [cell setImage:(!inactive ? uncheckedImage : checkImage)]; | |
285 | [tableView deselectRowAtIndexPath:(NSIndexPath *)indexPath animated:YES]; | |
286 | [self themesChanged]; | |
287 | } | |
288 | ||
289 | - (void) tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { | |
290 | NSUInteger fromIndex = [fromIndexPath row]; | |
291 | NSUInteger toIndex = [toIndexPath row]; | |
292 | if (fromIndex == toIndex) | |
293 | return; | |
294 | NSMutableDictionary *theme = [[[_themes objectAtIndex:fromIndex] retain] autorelease]; | |
295 | [_themes removeObjectAtIndex:fromIndex]; | |
296 | [_themes insertObject:theme atIndex:toIndex]; | |
297 | [self themesChanged]; | |
298 | } | |
299 | ||
300 | - (UITableViewCellEditingStyle) tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath { | |
301 | return UITableViewCellEditingStyleNone; | |
302 | } | |
303 | ||
304 | - (BOOL) tableView:(UITableView *)tableView shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath { | |
305 | return NO; | |
306 | } | |
307 | ||
308 | - (BOOL) tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { | |
309 | return YES; | |
310 | } | |
311 | /* }}} */ | |
312 | @end | |
313 | /* }}} */ | |
314 | ||
024f98ea | 315 | @interface WBAdvancedController: PSListController { |
224d48e3 JF |
316 | } |
317 | ||
224d48e3 JF |
318 | - (id) specifiers; |
319 | - (void) settingsChanged; | |
224d48e3 JF |
320 | |
321 | @end | |
322 | ||
024f98ea | 323 | @implementation WBAdvancedController |
224d48e3 | 324 | |
024f98ea JF |
325 | - (id) specifiers { |
326 | if (!_specifiers) | |
327 | _specifiers = [[self loadSpecifiersFromPlistName:@"Advanced" target:self] retain]; | |
328 | return _specifiers; | |
7c88a3f1 JF |
329 | } |
330 | ||
024f98ea JF |
331 | - (void) settingsChanged { |
332 | settingsChanged = YES; | |
333 | } | |
7c88a3f1 | 334 | |
024f98ea JF |
335 | - (void) setPreferenceValue:(id)value specifier:(PSSpecifier *)spec { |
336 | NSString *key([spec propertyForKey:@"key"]); | |
337 | if ([[spec propertyForKey:@"negate"] boolValue]) | |
338 | value = [NSNumber numberWithBool:(![value boolValue])]; | |
339 | [_settings setValue:value forKey:key]; | |
340 | [self settingsChanged]; | |
224d48e3 JF |
341 | } |
342 | ||
024f98ea JF |
343 | - (id) readPreferenceValue:(PSSpecifier *)spec { |
344 | NSString *key([spec propertyForKey:@"key"]); | |
345 | id defaultValue([spec propertyForKey:@"default"]); | |
346 | id plistValue([_settings objectForKey:key]); | |
347 | if (!plistValue) | |
348 | return defaultValue; | |
349 | if ([[spec propertyForKey:@"negate"] boolValue]) | |
350 | plistValue = [NSNumber numberWithBool:(![plistValue boolValue])]; | |
351 | return plistValue; | |
224d48e3 JF |
352 | } |
353 | ||
43fd3a0b | 354 | - (void) __optimizeThemes { |
265e19b2 JF |
355 | system("/usr/libexec/winterboard/Optimize"); |
356 | } | |
357 | ||
358 | - (void) optimizeThemes { | |
54a4cf27 | 359 | UIAlertView *alert([[[UIAlertView alloc] |
43fd3a0b | 360 | initWithTitle:@"Optimize Themes" |
54a4cf27 | 361 | message:@"Please note that this setting /replaces/ the PNG files that came with the theme. PNG files that have been iPhone-optimized cannot be viewed on a normal computer unless they are first deoptimized. You can use Cydia to reinstall themes that have been optimized in order to revert to the original PNG files." |
43fd3a0b | 362 | delegate:self |
54a4cf27 JF |
363 | cancelButtonTitle:@"Cancel" |
364 | otherButtonTitles:@"Optimize", nil | |
43fd3a0b JF |
365 | ] autorelease]); |
366 | ||
54a4cf27 JF |
367 | [alert setContext:@"optimize"]; |
368 | [alert setNumberOfRows:1]; | |
369 | [alert show]; | |
43fd3a0b JF |
370 | } |
371 | ||
372 | - (void) _optimizeThemes { | |
265e19b2 JF |
373 | UIView *view([self view]); |
374 | UIWindow *window([view window]); | |
375 | ||
376 | UIProgressHUD *hud([[[UIProgressHUD alloc] initWithWindow:window] autorelease]); | |
377 | [hud setText:@"Reticulating Splines\nPlease Wait (Minutes)"]; | |
378 | ||
379 | [window setUserInteractionEnabled:NO]; | |
380 | ||
381 | [window addSubview:hud]; | |
382 | [hud show:YES]; | |
43fd3a0b | 383 | [self wb$yieldToSelector:@selector(__optimizeThemes)]; |
265e19b2 JF |
384 | [hud removeFromSuperview]; |
385 | ||
386 | [window setUserInteractionEnabled:YES]; | |
387 | ||
388 | [self settingsChanged]; | |
389 | } | |
390 | ||
54a4cf27 JF |
391 | - (void) alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)button { |
392 | NSString *context([alert context]); | |
43fd3a0b JF |
393 | |
394 | if ([context isEqualToString:@"optimize"]) { | |
54a4cf27 JF |
395 | if (button == [alert firstOtherButtonIndex]) { |
396 | [self performSelector:@selector(_optimizeThemes) withObject:nil afterDelay:0]; | |
43fd3a0b JF |
397 | } |
398 | ||
54a4cf27 JF |
399 | [alert dismissWithClickedButtonIndex:-1 animated:YES]; |
400 | } | |
401 | /*else if ([super respondsToSelector:@selector(alertView:clickedButtonAtIndex:)]) | |
402 | [super alertView:alert clickedButtonAtIndex:button];*/ | |
43fd3a0b JF |
403 | } |
404 | ||
024f98ea JF |
405 | @end |
406 | ||
407 | @interface WBSettingsController: PSListController { | |
408 | } | |
409 | ||
410 | - (id) initForContentSize:(CGSize)size; | |
411 | - (void) dealloc; | |
412 | - (void) suspend; | |
413 | - (void) navigationBarButtonClicked:(int)buttonIndex; | |
414 | - (void) viewWillRedisplay; | |
415 | - (void) pushController:(id)controller; | |
416 | - (id) specifiers; | |
417 | - (void) settingsChanged; | |
418 | - (NSString *) title; | |
419 | - (void) setPreferenceValue:(id)value specifier:(PSSpecifier *)spec; | |
420 | - (id) readPreferenceValue:(PSSpecifier *)spec; | |
421 | ||
422 | @end | |
423 | ||
424 | @implementation WBSettingsController | |
425 | ||
426 | + (void) load { | |
e0c66475 | 427 | libhide = dlopen("/usr/lib/hide.dylib", RTLD_LAZY); |
024f98ea JF |
428 | IsIconHiddenDisplayId = reinterpret_cast<BOOL (*)(NSString *)>(dlsym(libhide, "IsIconHiddenDisplayId")); |
429 | HideIconViaDisplayId = reinterpret_cast<BOOL (*)(NSString *)>(dlsym(libhide, "HideIconViaDisplayId")); | |
430 | UnHideIconViaDisplayId = reinterpret_cast<BOOL (*)(NSString *)>(dlsym(libhide, "UnHideIconViaDisplayId")); | |
431 | } | |
432 | ||
34b51da8 JF |
433 | - (void) _wb$loadSettings { |
434 | _plist = [[NSString stringWithFormat:@"%@/Library/Preferences/com.saurik.WinterBoard.plist", NSHomeDirectory()] retain]; | |
435 | _settings = [NSMutableDictionary dictionaryWithContentsOfFile:_plist]; | |
436 | ||
437 | bool set; | |
438 | if (_settings != nil) | |
439 | set = true; | |
440 | else { | |
441 | set = false; | |
442 | _settings = [NSMutableDictionary dictionary]; | |
443 | } | |
d236b808 | 444 | |
34b51da8 | 445 | _settings = [_settings retain]; |
d236b808 | 446 | |
34b51da8 JF |
447 | if ([_settings objectForKey:@"SummerBoard"] == nil) |
448 | [_settings setObject:[NSNumber numberWithBool:set] forKey:@"SummerBoard"]; | |
024f98ea | 449 | |
e0c66475 JF |
450 | if (libhide != NULL) |
451 | [_settings setObject:[NSNumber numberWithBool:IsIconHiddenDisplayId(WinterBoardDisplayID)] forKey:@"IconHidden"]; | |
34b51da8 JF |
452 | } |
453 | ||
454 | - (id) initForContentSize:(CGSize)size { | |
455 | if ((self = [super initForContentSize:size]) != nil) { | |
456 | [self _wb$loadSettings]; | |
024f98ea JF |
457 | } return self; |
458 | } | |
459 | ||
460 | - (void) dealloc { | |
461 | [_settings release]; | |
462 | [_plist release]; | |
463 | [super dealloc]; | |
464 | } | |
465 | ||
224d48e3 JF |
466 | - (void) suspend { |
467 | if (!settingsChanged) | |
468 | return; | |
469 | ||
470 | NSData *data([NSPropertyListSerialization dataFromPropertyList:_settings format:NSPropertyListBinaryFormat_v1_0 errorDescription:NULL]); | |
471 | if (!data) | |
472 | return; | |
473 | if (![data writeToFile:_plist options:NSAtomicWrite error:NULL]) | |
474 | return; | |
475 | ||
e0c66475 JF |
476 | if (libhide != NULL) |
477 | ([[_settings objectForKey:@"IconHidden"] boolValue] ? HideIconViaDisplayId : UnHideIconViaDisplayId)(WinterBoardDisplayID); | |
7c88a3f1 | 478 | |
224d48e3 JF |
479 | unlink("/User/Library/Caches/com.apple.springboard-imagecache-icons"); |
480 | unlink("/User/Library/Caches/com.apple.springboard-imagecache-icons.plist"); | |
481 | unlink("/User/Library/Caches/com.apple.springboard-imagecache-smallicons"); | |
482 | unlink("/User/Library/Caches/com.apple.springboard-imagecache-smallicons.plist"); | |
bbea033b | 483 | |
546a205b JF |
484 | unlink("/User/Library/Caches/com.apple.SpringBoard.folderSwitcherLinen"); |
485 | unlink("/User/Library/Caches/com.apple.SpringBoard.notificationCenterLinen"); | |
bbea033b | 486 | |
546a205b JF |
487 | unlink("/User/Library/Caches/com.apple.SpringBoard.folderSwitcherLinen.0"); |
488 | unlink("/User/Library/Caches/com.apple.SpringBoard.folderSwitcherLinen.1"); | |
489 | unlink("/User/Library/Caches/com.apple.SpringBoard.folderSwitcherLinen.2"); | |
490 | unlink("/User/Library/Caches/com.apple.SpringBoard.folderSwitcherLinen.3"); | |
7c88a3f1 JF |
491 | |
492 | system("rm -rf /User/Library/Caches/SpringBoardIconCache"); | |
493 | system("rm -rf /User/Library/Caches/SpringBoardIconCache-small"); | |
f64efe8d | 494 | system("rm -rf /User/Library/Caches/com.apple.IconsCache"); |
546a205b | 495 | system("rm -rf /User/Library/Caches/com.apple.newsstand"); |
bbea033b | 496 | system("rm -rf /User/Library/Caches/com.apple.springboard.sharedimagecache"); |
7c88a3f1 | 497 | |
26bd2bf2 | 498 | system("killall -9 lsd"); |
c532a1cf JF |
499 | |
500 | if (kCFCoreFoundationVersionNumber > 700) // XXX: iOS 6.x | |
501 | system("killall backboardd"); | |
502 | else | |
503 | system("killall SpringBoard"); | |
224d48e3 JF |
504 | } |
505 | ||
b39b993d DH |
506 | - (void) cancelChanges { |
507 | [_settings release]; | |
508 | [_plist release]; | |
b39b993d | 509 | |
34b51da8 JF |
510 | [self _wb$loadSettings]; |
511 | ||
b39b993d DH |
512 | [self reloadSpecifiers]; |
513 | if (![[PSViewController class] instancesRespondToSelector:@selector(showLeftButton:withStyle:rightButton:withStyle:)]) { | |
1d3b613f JF |
514 | [[self navigationItem] setLeftBarButtonItem:nil]; |
515 | [[self navigationItem] setRightBarButtonItem:nil]; | |
838dbf4c DH |
516 | } else { |
517 | [self showLeftButton:nil withStyle:0 rightButton:nil withStyle:0]; | |
b39b993d DH |
518 | } |
519 | settingsChanged = NO; | |
520 | } | |
521 | ||
224d48e3 JF |
522 | - (void) navigationBarButtonClicked:(int)buttonIndex { |
523 | if (!settingsChanged) { | |
524 | [super navigationBarButtonClicked:buttonIndex]; | |
525 | return; | |
526 | } | |
527 | ||
838dbf4c | 528 | if (buttonIndex == 0) { |
b39b993d | 529 | [self cancelChanges]; |
838dbf4c DH |
530 | return; |
531 | } | |
224d48e3 JF |
532 | |
533 | [self suspend]; | |
534 | [self.rootController popController]; | |
535 | } | |
536 | ||
b39b993d DH |
537 | - (void) settingsConfirmButtonClicked:(UIBarButtonItem *)button { |
538 | [self navigationBarButtonClicked:button.tag]; | |
539 | } | |
540 | ||
224d48e3 JF |
541 | - (void) viewWillRedisplay { |
542 | if (settingsChanged) | |
543 | [self settingsChanged]; | |
544 | [super viewWillRedisplay]; | |
545 | } | |
546 | ||
b39b993d DH |
547 | - (void) viewWillAppear:(BOOL)animated { |
548 | if (settingsChanged) | |
549 | [self settingsChanged]; | |
1d3b613f JF |
550 | if ([super respondsToSelector:@selector(viewWillAppear:)]) |
551 | [super viewWillAppear:animated]; | |
b39b993d DH |
552 | } |
553 | ||
224d48e3 JF |
554 | - (void) pushController:(id)controller { |
555 | [self hideNavigationBarButtons]; | |
556 | [super pushController:controller]; | |
557 | } | |
558 | ||
559 | - (id) specifiers { | |
560 | if (!_specifiers) | |
561 | _specifiers = [[self loadSpecifiersFromPlistName:@"WinterBoard" target:self] retain]; | |
562 | return _specifiers; | |
563 | } | |
564 | ||
565 | - (void) settingsChanged { | |
b39b993d DH |
566 | if (![[PSViewController class] instancesRespondToSelector:@selector(showLeftButton:withStyle:rightButton:withStyle:)]) { |
567 | UIBarButtonItem *respringButton([[UIBarButtonItem alloc] initWithTitle:@"Respring" style:UIBarButtonItemStyleDone target:self action:@selector(settingsConfirmButtonClicked:)]); | |
568 | UIBarButtonItem *cancelButton([[UIBarButtonItem alloc] initWithTitle:@"Cancel" style:UIBarButtonItemStylePlain target:self action:@selector(settingsConfirmButtonClicked:)]); | |
569 | cancelButton.tag = 0; | |
570 | respringButton.tag = 1; | |
1d3b613f JF |
571 | [[self navigationItem] setLeftBarButtonItem:respringButton]; |
572 | [[self navigationItem] setRightBarButtonItem:cancelButton]; | |
b39b993d DH |
573 | [respringButton release]; |
574 | [cancelButton release]; | |
575 | } else { | |
576 | [self showLeftButton:@"Respring" withStyle:2 rightButton:@"Cancel" withStyle:0]; | |
577 | } | |
224d48e3 JF |
578 | settingsChanged = YES; |
579 | } | |
580 | ||
581 | - (NSString *) title { | |
582 | return @"WinterBoard"; | |
583 | } | |
584 | ||
585 | - (void) setPreferenceValue:(id)value specifier:(PSSpecifier *)spec { | |
7c88a3f1 | 586 | NSString *key([spec propertyForKey:@"key"]); |
224d48e3 JF |
587 | if ([[spec propertyForKey:@"negate"] boolValue]) |
588 | value = [NSNumber numberWithBool:(![value boolValue])]; | |
7c88a3f1 | 589 | [_settings setValue:value forKey:key]; |
224d48e3 JF |
590 | [self settingsChanged]; |
591 | } | |
592 | ||
593 | - (id) readPreferenceValue:(PSSpecifier *)spec { | |
594 | NSString *key([spec propertyForKey:@"key"]); | |
595 | id defaultValue([spec propertyForKey:@"default"]); | |
596 | id plistValue([_settings objectForKey:key]); | |
597 | if (!plistValue) | |
598 | return defaultValue; | |
599 | if ([[spec propertyForKey:@"negate"] boolValue]) | |
600 | plistValue = [NSNumber numberWithBool:(![plistValue boolValue])]; | |
601 | return plistValue; | |
602 | } | |
603 | ||
604 | @end | |
b39b993d DH |
605 | |
606 | #define WBSAddMethod(_class, _sel, _imp, _type) \ | |
607 | if (![[_class class] instancesRespondToSelector:@selector(_sel)]) \ | |
608 | class_addMethod([_class class], @selector(_sel), (IMP)_imp, _type) | |
609 | void $PSRootController$popController(PSRootController *self, SEL _cmd) { | |
610 | [self popViewControllerAnimated:YES]; | |
611 | } | |
612 | ||
613 | void $PSViewController$hideNavigationBarButtons(PSRootController *self, SEL _cmd) { | |
614 | } | |
615 | ||
616 | id $PSViewController$initForContentSize$(PSRootController *self, SEL _cmd, CGRect contentSize) { | |
617 | return [self init]; | |
618 | } | |
619 | ||
620 | static __attribute__((constructor)) void __wbsInit() { | |
621 | WBSAddMethod(PSRootController, popController, $PSRootController$popController, "v@:"); | |
622 | WBSAddMethod(PSViewController, hideNavigationBarButtons, $PSViewController$hideNavigationBarButtons, "v@:"); | |
623 | WBSAddMethod(PSViewController, initForContentSize:, $PSViewController$initForContentSize$, "@@:{ff}"); | |
624 | } |