+void AddThemes(NSMutableArray *themesOnDisk, NSString *folder) {
+ NSArray *themes([[NSFileManager defaultManager] contentsOfDirectoryAtPath:folder error:NULL]);
+ for (NSString *theme in themes) {
+ if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/%@/Info.plist", folder, theme]]) {
+ if (NSArray *version = [info objectForKey:@"CoreFoundationVersion"]) {
+ size_t count([version count]);
+ if (count == 0 || count > 2)
+ continue;
+
+ double lower([[version objectAtIndex:0] doubleValue]);
+ if (kCFCoreFoundationVersionNumber < lower)
+ continue;
+
+ if (count != 1) {
+ double upper([[version objectAtIndex:1] doubleValue]);
+ if (upper <= kCFCoreFoundationVersionNumber)
+ continue;
+ }
+ }
+ }
+
+ [themesOnDisk addObject:theme];
+ }
+}
+
+static void RestartSpringBoard() {
+ 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");
+
+ unlink("/User/Library/Caches/com.apple.SpringBoard.folderSwitcherLinen");
+ unlink("/User/Library/Caches/com.apple.SpringBoard.notificationCenterLinen");
+
+ unlink("/User/Library/Caches/com.apple.SpringBoard.folderSwitcherLinen.0");
+ unlink("/User/Library/Caches/com.apple.SpringBoard.folderSwitcherLinen.1");
+ unlink("/User/Library/Caches/com.apple.SpringBoard.folderSwitcherLinen.2");
+ unlink("/User/Library/Caches/com.apple.SpringBoard.folderSwitcherLinen.3");
+
+ system("rm -rf /User/Library/Caches/SpringBoardIconCache");
+ system("rm -rf /User/Library/Caches/SpringBoardIconCache-small");
+ system("rm -rf /User/Library/Caches/com.apple.IconsCache");
+ system("rm -rf /User/Library/Caches/com.apple.newsstand");
+ system("rm -rf /User/Library/Caches/com.apple.springboard.sharedimagecache");
+ system("rm -rf /User/Library/Caches/com.apple.UIStatusBar");
+
+ system("rm -rf /User/Library/Caches/BarDialer");
+ system("rm -rf /User/Library/Caches/BarDialer_selected");
+ system("rm -rf /User/Library/Caches/BarRecents");
+ system("rm -rf /User/Library/Caches/BarRecents_selected");
+ system("rm -rf /User/Library/Caches/BarVM");
+ system("rm -rf /User/Library/Caches/BarVM_selected");
+
+ system("killall -9 lsd");
+
+ if (kCFCoreFoundationVersionNumber > 700) // XXX: iOS 6.x
+ system("killall backboardd");
+ else
+ system("killall SpringBoard");
+}
+
+/* [NSObject yieldToSelector:(withObject:)] {{{*/
+@interface NSObject (wb$yieldToSelector)
+- (id) wb$yieldToSelector:(SEL)selector withObject:(id)object;
+- (id) wb$yieldToSelector:(SEL)selector;
+@end
+
+@implementation NSObject (Cydia)
+
+- (void) wb$doNothing {
+}
+
+- (void) wb$_yieldToContext:(NSMutableArray *)context {
+ NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
+
+ SEL selector(reinterpret_cast<SEL>([[context objectAtIndex:0] pointerValue]));
+ id object([[context objectAtIndex:1] nonretainedObjectValue]);
+ volatile bool &stopped(*reinterpret_cast<bool *>([[context objectAtIndex:2] pointerValue]));
+
+ /* XXX: deal with exceptions */
+ id value([self performSelector:selector withObject:object]);
+
+ NSMethodSignature *signature([self methodSignatureForSelector:selector]);
+ [context removeAllObjects];
+ if ([signature methodReturnLength] != 0 && value != nil)
+ [context addObject:value];
+
+ stopped = true;
+
+ [self
+ performSelectorOnMainThread:@selector(wb$doNothing)
+ withObject:nil
+ waitUntilDone:NO
+ ];
+
+ [pool release];
+}
+
+- (id) wb$yieldToSelector:(SEL)selector withObject:(id)object {
+ /*return [self performSelector:selector withObject:object];*/
+
+ volatile bool stopped(false);
+
+ NSMutableArray *context([NSMutableArray arrayWithObjects:
+ [NSValue valueWithPointer:selector],
+ [NSValue valueWithNonretainedObject:object],
+ [NSValue valueWithPointer:const_cast<bool *>(&stopped)],
+ nil]);
+
+ NSThread *thread([[[NSThread alloc]
+ initWithTarget:self
+ selector:@selector(wb$_yieldToContext:)
+ object:context
+ ] autorelease]);
+
+ [thread start];
+
+ NSRunLoop *loop([NSRunLoop currentRunLoop]);
+ NSDate *future([NSDate distantFuture]);
+
+ while (!stopped && [loop runMode:NSDefaultRunLoopMode beforeDate:future]);
+
+ return [context count] == 0 ? nil : [context objectAtIndex:0];
+}
+
+- (id) wb$yieldToSelector:(SEL)selector {
+ return [self wb$yieldToSelector:selector withObject:nil];
+}
+
+@end
+/* }}} */
+