X-Git-Url: https://git.saurik.com/winterboard.git/blobdiff_plain/9c64bab2dec3058f7f247ae70281020982845877..240a7a4e7d5b9af9e83e99bcb08cf37e95f53922:/Application.mm diff --git a/Application.mm b/Application.mm index 1996955..772cc07 100644 --- a/Application.mm +++ b/Application.mm @@ -1,233 +1,174 @@ /* WinterBoard - Theme Manager for the iPhone - * Copyright (C) 2008 Jay Freeman (saurik) + * Copyright (C) 2008-2014 Jay Freeman (saurik) */ +/* GNU Lesser General Public License, Version 3 {{{ */ /* - * Redistribution and use in source and binary - * forms, with or without modification, are permitted - * provided that the following conditions are met: + * WinterBoard is free software: you can redistribute it and/or modify it under + * the terms of the GNU Lesser General Public License as published by the + * Free Software Foundation, either version 3 of the License, or (at your + * option) any later version. * - * 1. Redistributions of source code must retain the - * above copyright notice, this list of conditions - * and the following disclaimer. - * 2. Redistributions in binary form must reproduce the - * above copyright notice, this list of conditions - * and the following disclaimer in the documentation - * and/or other materials provided with the - * distribution. - * 3. The name of the author may not be used to endorse - * or promote products derived from this software - * without specific prior written permission. + * WinterBoard is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public + * License for more details. * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, - * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, - * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT - * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF - * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR - * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN - * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF - * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -*/ + * You should have received a copy of the GNU Lesser General Public License + * along with WinterBoard. If not, see . +**/ +/* }}} */ #import #import #import -#define _trace() NSLog(@"WE:_trace(%u)", __LINE__); +#include -static NSString *plist_; -static NSMutableDictionary *settings_; -static BOOL changed_; +#import +#import +#import +#import -@interface WBThemeTableViewCell : UITableViewCell { - UILabel *label; -} +#include + +static NSBundle *wbSettingsBundle; +static Class $WBSettingsController; +@interface UIApplication (Private) +- (void) terminateWithSuccess; @end -@implementation WBThemeTableViewCell +@interface UIDevice (Private) +- (BOOL) isWildcat; +@end +@interface PSRootController (Compatibility) +- (id) _popController; // < 3.2 +- (id) contentView; // < 3.2 +- (id) lastController; // < 3.2 +- (id) topViewController; // >= 3.2 +@end +@interface PSListController (Compatibility) +- (void) viewWillBecomeVisible:(void *)specifier; // < 3.2 +- (void) viewWillAppear:(BOOL)a; // >= 3.2 +- (void) setSpecifier:(PSSpecifier *)spec; // >= 3.2 @end -@interface WBApplication : UIApplication < - UITableViewDataSource, - UITableViewDelegate -> { - UIWindow *window_; - UITableView *themesTable_; - NSMutableArray *themesArray_; +@interface WBRootController : PSRootController { + PSListController *_rootListController; } +@property (readonly) PSListController *rootListController; + +- (void) setupRootListForSize:(CGSize)size; +- (id) topViewController; @end -@implementation WBApplication +@implementation WBRootController -- (void) dealloc { - [window_ release]; - [themesTable_ release]; - [themesArray_ release]; - [super dealloc]; -} +@synthesize rootListController = _rootListController; -- (void) applicationWillTerminate:(UIApplication *)application { - if (changed_) { - NSString *description = nil; - NSData *data = [NSPropertyListSerialization dataFromPropertyList:settings_ format:NSPropertyListBinaryFormat_v1_0 errorDescription:&description]; - if (data == nil) { - NSLog(@"WB:Error:dataFromPropertyList:%@", description); - return; - } - - NSError *error = nil; - if (![data writeToFile:plist_ options:NSAtomicWrite error:&error]) { - NSLog(@"WB:Error:writeToFile"); - return; - } - - unlink("/User/Library/Caches/com.apple.springboard-imagecache-icons"); - unlink("/User/Library/Caches/com.apple.springboard-imagecache-icons.plist"); - - unlink("/User/Library/Caches/com.apple.springboard-imagecache-smallicons"); - unlink("/User/Library/Caches/com.apple.springboard-imagecache-smallicons.plist"); - - system("killall SpringBoard"); - } -} +// < 3.2 +- (void) setupRootListForSize:(CGSize)size { + PSSpecifier *spec([[PSSpecifier alloc] init]); + [spec setTarget:self]; + spec.name = @"WinterBoard"; -- (UITableViewCell *) tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { - UITableViewCell *cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero] autorelease]; - NSMutableDictionary *theme = [themesArray_ objectAtIndex:[indexPath row]]; - cell.text = [theme objectForKey:@"Name"]; - cell.hidesAccessoryWhenEditing = NO; - NSNumber *active = [theme objectForKey:@"Active"]; - BOOL inactive = active == nil || ![active boolValue]; - cell.accessoryType = inactive ? UITableViewCellAccessoryNone : UITableViewCellAccessoryCheckmark; - return cell; -} + _rootListController = [[$WBSettingsController alloc] initForContentSize:size]; + _rootListController.rootController = self; + _rootListController.parentController = self; + [_rootListController viewWillBecomeVisible:spec]; -- (void) tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { - UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; - NSMutableDictionary *theme = [themesArray_ objectAtIndex:[indexPath row]]; - NSNumber *active = [theme objectForKey:@"Active"]; - BOOL inactive = active == nil || ![active boolValue]; - [theme setObject:[NSNumber numberWithBool:inactive] forKey:@"Active"]; - cell.accessoryType = inactive ? UITableViewCellAccessoryCheckmark : UITableViewCellAccessoryNone; - [themesTable_ deselectRowAtIndexPath:(NSIndexPath *)indexPath animated:YES]; - changed_ = YES; -} + [spec release]; -- (NSInteger) tableView:(UITableView *)table numberOfRowsInSection:(NSInteger)section { - return [themesArray_ count]; + [self pushController:_rootListController]; } -- (UITableViewCellEditingStyle) tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath { - return UITableViewCellEditingStyleNone; +// >= 3.2 +- (void) loadView { + [super loadView]; + [self pushViewController:[self rootListController] animated:NO]; } -- (void) tableView:(UITableView *)tableView moveRowAtIndexPath:(NSIndexPath *)fromIndexPath toIndexPath:(NSIndexPath *)toIndexPath { - NSUInteger fromIndex = [fromIndexPath row]; - NSUInteger toIndex = [toIndexPath row]; - if (fromIndex == toIndex) - return; - NSMutableDictionary *theme = [[[themesArray_ objectAtIndex:fromIndex] retain] autorelease]; - [themesArray_ removeObjectAtIndex:fromIndex]; - [themesArray_ insertObject:theme atIndex:toIndex]; - changed_ = YES; +- (PSListController *) rootListController { + if(!_rootListController) { + PSSpecifier *spec([[PSSpecifier alloc] init]); + [spec setTarget:self]; + spec.name = @"WinterBoard"; + _rootListController = [[$WBSettingsController alloc] initForContentSize:CGSizeZero]; + _rootListController.rootController = self; + _rootListController.parentController = self; + [_rootListController setSpecifier:spec]; + [spec release]; + } + return _rootListController; } -- (BOOL) tableView:(UITableView *)tableView canMoveRowAtIndexPath:(NSIndexPath *)indexPath { - return YES; +- (id) contentView { + if ([[PSRootController class] instancesRespondToSelector:@selector(contentView)]) { + return [super contentView]; + } else { + return [super view]; + } } -- (void) applicationDidFinishLaunching:(id)unused { - window_ = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].applicationFrame]; - [window_ makeKeyAndVisible]; - - plist_ = [[NSString stringWithFormat:@"%@/Library/Preferences/com.saurik.WinterBoard.plist", - NSHomeDirectory() - ] retain]; - - settings_ = [[NSMutableDictionary alloc] initWithContentsOfFile:plist_]; - if (settings_ == nil) - settings_ = [[NSMutableDictionary alloc] initWithCapacity:16]; - - themesArray_ = [settings_ objectForKey:@"Themes"]; - if (themesArray_ == nil) { - if (NSString *theme = [settings_ objectForKey:@"Theme"]) { - themesArray_ = [[NSArray arrayWithObject:[[NSDictionary dictionaryWithObjectsAndKeys: - theme, @"Name", - [NSNumber numberWithBool:YES], @"Active", - nil] mutableCopy]] mutableCopy]; - - [settings_ removeObjectForKey:@"Theme"]; - } - - if (themesArray_ == nil) - themesArray_ = [NSMutableArray arrayWithCapacity:16]; - [settings_ setObject:themesArray_ forKey:@"Themes"]; +- (id) topViewController { + if ([[PSRootController class] instancesRespondToSelector:@selector(topViewController)]) { + return [super topViewController]; + } else { + return [super lastController]; } +} - themesArray_ = [themesArray_ retain]; - - NSMutableSet *themesSet = [NSMutableSet setWithCapacity:32]; - for (NSMutableDictionary *theme in themesArray_) - if (NSString *name = [theme objectForKey:@"Name"]) - [themesSet addObject:name]; - - NSFileManager *manager = [NSFileManager defaultManager]; - - NSMutableArray *themes = [NSMutableArray arrayWithCapacity:32]; - [themes addObjectsFromArray:[manager contentsOfDirectoryAtPath:@"/Library/Themes" error:NULL]]; - [themes addObjectsFromArray:[manager contentsOfDirectoryAtPath:[NSString stringWithFormat:@"%@/Library/SummerBoard/Themes", NSHomeDirectory()] error:NULL]]; +- (void) _popController { + // Pop the last controller = exit the application. + // The only time the last controller should pop is when the user taps Respring/Cancel. + // Which only gets displayed if the user has made changes. + if ([self topViewController] == _rootListController) + [[UIApplication sharedApplication] terminateWithSuccess]; + [super _popController]; +} - for (NSUInteger i(0), e([themes count]); i != e; ++i) { - NSString *theme = [themes objectAtIndex:i]; - if ([theme hasSuffix:@".theme"]) - [themes replaceObjectAtIndex:i withObject:[theme substringWithRange:NSMakeRange(0, [theme length] - 6)]]; - } +@end - for (NSUInteger i(0), e([themesArray_ count]); i != e; ++i) { - NSMutableDictionary *theme = [themesArray_ objectAtIndex:i]; - NSString *name = [theme objectForKey:@"Name"]; - if (name == nil || ![themes containsObject:name]) { - [themesArray_ removeObjectAtIndex:i]; - --i; --e; - } - } +@interface WBApplication : UIApplication { + WBRootController *_rootController; +} - for (NSString *theme in themes) { - if ([themesSet containsObject:theme]) - continue; - [themesSet addObject:theme]; - [themesArray_ insertObject:[[NSDictionary dictionaryWithObjectsAndKeys: - theme, @"Name", - [NSNumber numberWithBool:NO], @"Active", - nil] mutableCopy] atIndex:0]; - } +@end - themesTable_ = [[UITableView alloc] initWithFrame:window_.bounds]; - [window_ addSubview:themesTable_]; +@implementation WBApplication - [themesTable_ setDataSource:self]; - [themesTable_ setDelegate:self]; +- (void) dealloc { + [_rootController release]; + [super dealloc]; +} - [themesTable_ setEditing:YES animated:NO]; - themesTable_.allowsSelectionDuringEditing = YES; +- (void) applicationWillTerminate:(UIApplication *)application { + [_rootController.rootListController suspend]; +} - [themesTable_ setSeparatorStyle:UITableViewCellSeparatorStyleSingleLine]; +- (void) applicationDidFinishLaunching:(id)unused { + wbSettingsBundle = [NSBundle bundleWithPath:@"/System/Library/PreferenceBundles/WinterBoardSettings.bundle"]; + [wbSettingsBundle load]; + $WBSettingsController = [wbSettingsBundle principalClass]; + + CGRect applicationFrame(([UIDevice instancesRespondToSelector:@selector(isWildcat)] + && [[UIDevice currentDevice] isWildcat]) || objc_getClass("UIStatusBar") != nil + ? [UIScreen mainScreen].bounds + : [UIScreen mainScreen].applicationFrame); + UIWindow *window([[UIWindow alloc] initWithFrame:applicationFrame]); + _rootController = [[WBRootController alloc] initWithTitle:@"WinterBoard" identifier:[[NSBundle mainBundle] bundleIdentifier]]; + [window addSubview:[_rootController contentView]]; + [window makeKeyAndVisible]; } @end int main(int argc, char *argv[]) { - NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + NSAutoreleasePool *pool( [[NSAutoreleasePool alloc] init]); int value = UIApplicationMain(argc, argv, @"WBApplication", @"WBApplication");