1 /* WinterBoard - Theme Manager for the iPhone
2 * Copyright (C) 2008-2011 Jay Freeman (saurik)
6 * Redistribution and use in source and binary
7 * forms, with or without modification, are permitted
8 * provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the
11 * above copyright notice, this list of conditions
12 * and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the
14 * above copyright notice, this list of conditions
15 * and the following disclaimer in the documentation
16 * and/or other materials provided with the
18 * 3. The name of the author may not be used to endorse
19 * or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
33 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 #define _trace() do { \
44 struct timeval _ctv; \
45 gettimeofday(&_ctv, NULL); \
50 NSLog(@"%lu.%.6u[%f]:WB:_trace()@%s:%u[%s]\n", \
51 _ctv.tv_sec, _ctv.tv_usec, \
52 (_ctv.tv_sec - _ltv.tv_sec) + (_ctv.tv_usec - _ltv.tv_usec) / 1000000.0, \
53 __FILE__, __LINE__, __FUNCTION__\
60 #import <CoreFoundation/CoreFoundation.h>
61 #import <Foundation/Foundation.h>
62 #import <CoreGraphics/CoreGraphics.h>
63 #import <ImageIO/CGImageSource.h>
65 #import <Celestial/AVController.h>
66 #import <Celestial/AVItem.h>
67 #import <Celestial/AVQueue.h>
69 #include <substrate.h>
71 #import <UIKit/UIKit.h>
73 #import <SpringBoard/SBApplication.h>
74 #import <SpringBoard/SBApplicationIcon.h>
75 #import <SpringBoard/SBAppWindow.h>
76 #import <SpringBoard/SBAwayView.h>
77 #import <SpringBoard/SBBookmarkIcon.h>
78 #import <SpringBoard/SBButtonBar.h>
79 #import <SpringBoard/SBCalendarIconContentsView.h>
80 #import <SpringBoard/SBIconController.h>
81 #import <SpringBoard/SBIconLabel.h>
82 #import <SpringBoard/SBIconList.h>
83 #import <SpringBoard/SBIconModel.h>
84 #import <SpringBoard/SBImageCache.h>
85 // XXX: #import <SpringBoard/SBSearchView.h>
86 #import <SpringBoard/SBSearchTableViewCell.h>
87 #import <SpringBoard/SBStatusBarContentsView.h>
88 #import <SpringBoard/SBStatusBarController.h>
89 #import <SpringBoard/SBStatusBarOperatorNameView.h>
90 #import <SpringBoard/SBStatusBarTimeView.h>
91 #import <SpringBoard/SBUIController.h>
92 #import <SpringBoard/SBWidgetApplicationIcon.h>
94 #import <MobileSMS/mSMSMessageTranscriptController.h>
96 #import <MediaPlayer/MPMoviePlayerController.h>
97 #import <MediaPlayer/MPVideoView.h>
98 #import <MediaPlayer/MPVideoView-PlaybackControl.h>
100 #import <CoreGraphics/CGGeometry.h>
102 #import <ChatKit/CKMessageCell.h>
104 #include <sys/sysctl.h>
106 #include "WBMarkup.h"
108 extern "C" void __clear_cache (char *beg, char *end);
110 @protocol WinterBoard
114 Class $MPMoviePlayerController;
117 MSClassHook(NSBundle)
118 MSClassHook(NSString)
121 MSMetaClassHook(UIImage)
122 MSClassHook(UINavigationBar)
123 MSClassHook(UIToolbar)
125 MSClassHook(CKBalloonView)
126 MSClassHook(CKMessageCell)
127 MSClassHook(CKTimestampView)
128 MSClassHook(CKTranscriptCell)
129 MSClassHook(CKTranscriptController)
130 MSClassHook(CKTranscriptHeaderView)
131 MSClassHook(CKTranscriptTableView)
133 MSClassHook(SBApplication)
134 MSClassHook(SBApplicationIcon)
135 MSClassHook(SBAwayView)
136 MSClassHook(SBBookmarkIcon)
137 MSClassHook(SBButtonBar)
138 MSClassHook(SBCalendarApplicationIcon)
139 MSClassHook(SBCalendarIconContentsView)
140 MSClassHook(SBDockIconListView)
142 MSClassHook(SBIconBadge)
143 MSClassHook(SBIconBadgeFactory)
144 MSClassHook(SBIconController)
145 MSClassHook(SBIconLabel)
146 MSClassHook(SBIconList)
147 MSClassHook(SBIconModel)
148 //MSClassHook(SBImageCache)
149 MSClassHook(SBSearchView)
150 MSClassHook(SBSearchTableViewCell)
151 MSClassHook(SBSlidingAlertDisplay)
152 MSClassHook(SBStatusBarContentsView)
153 MSClassHook(SBStatusBarController)
154 MSClassHook(SBStatusBarOperatorNameView)
155 MSClassHook(SBStatusBarTimeView)
156 MSClassHook(SBUIController)
157 MSClassHook(SBWallpaperView)
158 MSClassHook(SBWidgetApplicationIcon)
160 extern "C" void WKSetCurrentGraphicsContext(CGContextRef);
162 __attribute__((__constructor__))
163 static void MSFixClass() {
165 $SBIcon = objc_getClass("SBIconView");
166 if ($CKTranscriptController == nil)
167 $CKTranscriptController = objc_getClass("mSMSMessageTranscriptController");
171 static bool Four_($SBDockIconListView != nil);
173 @interface NSDictionary (WinterBoard)
174 - (UIColor *) wb$colorForKey:(NSString *)key;
175 - (BOOL) wb$boolForKey:(NSString *)key;
178 @implementation NSDictionary (WinterBoard)
180 - (UIColor *) wb$colorForKey:(NSString *)key {
181 NSString *value = [self objectForKey:key];
188 - (BOOL) wb$boolForKey:(NSString *)key {
189 if (NSString *value = [self objectForKey:key])
190 return [value boolValue];
196 static BOOL (*_GSFontGetUseLegacyFontMetrics)();
197 #define $GSFontGetUseLegacyFontMetrics() \
198 (_GSFontGetUseLegacyFontMetrics == NULL ? YES : _GSFontGetUseLegacyFontMetrics())
200 static bool Debug_ = false;
201 static bool UIDebug_ = false;
202 static bool Engineer_ = false;
203 static bool SummerBoard_ = true;
204 static bool SpringBoard_;
206 static UIImage *(*_UIApplicationImageWithName)(NSString *name);
207 static UIImage *(*_UIImageWithNameInDomain)(NSString *name, NSString *domain);
208 static NSBundle *(*_UIKitBundle)();
209 static bool (*_UIPackedImageTableGetIdentifierForName)(NSString *, int *);
210 static int (*_UISharedImageNameGetIdentifier)(NSString *);
212 static NSMutableDictionary *UIImages_ = [[NSMutableDictionary alloc] initWithCapacity:32];
213 static NSMutableDictionary *PathImages_ = [[NSMutableDictionary alloc] initWithCapacity:16];
214 static NSMutableDictionary *Cache_ = [[NSMutableDictionary alloc] initWithCapacity:64];
215 static NSMutableDictionary *Strings_ = [[NSMutableDictionary alloc] initWithCapacity:0];
216 static NSMutableDictionary *Bundles_ = [[NSMutableDictionary alloc] initWithCapacity:2];
218 static NSFileManager *Manager_;
219 static NSMutableArray *Themes_;
221 static NSDictionary *English_;
222 static NSMutableDictionary *Info_;
225 static NSMutableDictionary *Themed_ = [[NSMutableDictionary alloc] initWithCapacity:128];
227 static unsigned Scale_ = 0;
229 static unsigned $getScale$(NSString *path) {
230 NSString *name(path);
232 #define StripName(strip) \
233 if ([name hasSuffix:@ strip]) \
234 name = [name substringWithRange:NSMakeRange(0, [name length] - sizeof(strip) - 1)];
238 StripName("~iphone");
241 return [name hasSuffix:@"@2x"] ? 2 : 1;
244 static NSArray *$useScale$(NSArray *files, bool use = true) {
245 if (use && Scale_ == 0) {
246 UIScreen *screen([UIScreen mainScreen]);
247 if ([screen respondsToSelector:@selector(scale)])
248 Scale_ = [screen scale];
256 NSString *idiom(IsWild_ ? @"ipad" : @"iphone");
258 NSMutableArray *scaled([NSMutableArray arrayWithCapacity:([files count] * 4)]);
260 for (NSString *file in files) {
261 NSString *base([file stringByDeletingPathExtension]);
262 NSString *extension([file pathExtension]);
266 [scaled addObject:[NSString stringWithFormat:@"%@@2x~%@.%@", base, idiom, extension]];
268 [scaled addObject:[NSString stringWithFormat:@"%@@2x.%@", base, extension]];
271 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
273 // if (!IsWild_) <- support old themes
274 [scaled addObject:file];
275 } else if ([base hasSuffix: @"@2x"]) {
276 [scaled addObject:[NSString stringWithFormat:@"%@~iphone.%@", base, extension]];
277 [scaled addObject:file];
279 // XXX: this actually can't be used, as the person loading the file doesn't realize that the @2x changed
280 /*NSString *rest([base substringWithRange:NSMakeRange(0, [base length] - 3)]);
281 [scaled addObject:[NSString stringWithFormat:@"%@~iphone.%@", rest, extension]];
282 [scaled addObject:[rest stringByAppendingPathExtension:extension]];*/
284 // XXX: this code isn't really complete
286 [scaled addObject:file];
288 if ([base hasSuffix:@"~iphone"])
289 [scaled addObject:[[base substringWithRange:NSMakeRange(0, [base length] - 7)] stringByAppendingPathExtension:extension]];
296 static NSString *$getTheme$(NSArray *files, NSArray *themes = Themes_) {
297 if (NSString *path = [Themed_ objectForKey:files])
298 return reinterpret_cast<id>(path) == [NSNull null] ? nil : path;
301 NSLog(@"WB:Debug: %@", [files description]);
305 for (NSString *theme in Themes_)
306 for (NSString *file in files) {
307 path = [NSString stringWithFormat:@"%@/%@", theme, file];
308 if ([Manager_ fileExistsAtPath:path])
315 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:files];
319 // $pathForFile$inBundle$() {{{
320 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool ui) {
321 NSString *identifier = [bundle bundleIdentifier];
322 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
324 if (identifier != nil)
325 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
326 if (NSString *folder = [[bundle bundlePath] lastPathComponent])
327 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
329 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
331 #define remapResourceName(oldname, newname) \
332 else if ([file isEqualToString:(oldname)]) \
333 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
335 bool summer(SpringBoard_ && SummerBoard_);
337 if (identifier == nil);
338 else if ([identifier isEqualToString:@"com.apple.chatkit"])
339 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
340 else if ([identifier isEqualToString:@"com.apple.calculator"])
341 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
343 remapResourceName(@"FSO_BG.png", @"StatusBar")
344 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
345 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
347 if (NSString *path = $getTheme$($useScale$(names, ui)))
354 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
355 NSString *identifier = [self bundleIdentifier];
356 NSString *path = [self path];
357 NSString *folder = [path lastPathComponent];
358 NSString *dname = [self displayName];
359 NSString *didentifier = [self displayIdentifier];
362 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
364 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
366 /* XXX: I might need to keep this for backwards compatibility
367 if (identifier != nil)
368 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
370 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
372 #define testForIcon(Name) \
373 if (NSString *name = Name) \
374 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
376 if (![didentifier isEqualToString:identifier])
377 testForIcon(didentifier);
379 testForIcon(identifier);
382 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
385 if (didentifier != nil) {
386 testForIcon([English_ objectForKey:didentifier]);
388 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
389 if ([parts count] != 1)
390 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
391 testForIcon([english objectForKey:[parts lastObject]]);
394 if (NSString *path = $getTheme$(names))
400 // -[NSBundle wb$bundleWithFile] {{{
401 @interface NSBundle (WinterBoard)
402 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
405 @implementation NSBundle (WinterBoard)
407 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
408 path = [path stringByDeletingLastPathComponent];
409 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
412 NSBundle *bundle([Bundles_ objectForKey:path]);
413 if (reinterpret_cast<id>(bundle) == [NSNull null])
415 else if (bundle == nil) {
416 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
417 bundle = [NSBundle bundleWithPath:path];
419 bundle = [NSBundle wb$bundleWithFile:path];
421 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
422 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
430 // -[NSString wb$themedPath] {{{
431 @interface NSString (WinterBoard)
432 - (NSString *) wb$themedPath;
435 @implementation NSString (WinterBoard)
437 - (NSString *) wb$themedPath {
438 if ([self hasPrefix:@"/Library/Themes/"])
442 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
444 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
445 NSString *file([self stringByResolvingSymlinksInPath]);
446 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
447 if ([file hasPrefix:prefix]) {
448 NSUInteger length([prefix length]);
449 if (length != [file length])
450 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
461 void WBLogRect(const char *tag, struct CGRect rect) {
462 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
465 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
466 CGRect frame([view frame]);
467 NSLog(@"%*s|%2d:%p:%s : {%f,%f+%f,%f} (%@)", indent * 3, "", index, view, class_getName([view class]), frame.origin.x, frame.origin.y, frame.size.width, frame.size.height, [view backgroundColor]);
469 for (UIView *child in [view subviews])
470 WBLogHierarchy(child, index++, indent + 1);
473 UIImage *$cacheForImage$(UIImage *image) {
474 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
475 CGRect rect = {CGPointMake(1, 1), [image size]};
476 CGSize size = {rect.size.width + 2, rect.size.height + 2};
478 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
479 CGColorSpaceRelease(space);
481 CGContextDrawImage(context, rect, [image CGImage]);
482 CGImageRef ref(CGBitmapContextCreateImage(context));
483 CGContextRelease(context);
485 UIImage *cache([UIImage imageWithCGImage:ref]);
491 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
492 //if ([name isEqualToString:@"icons"]) return nil;
493 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
496 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
497 NSString *key([icon displayIdentifier]);
499 if (UIImage *image = [icon icon]) {
500 CGSize size = [image size];
501 if (size.width != 59 || size.height != 60) {
502 UIImage *cache($cacheForImage$(image));
503 [Cache_ setObject:cache forKey:key];
508 _SBIconModel$cacheImageForIcon$(self, sel, icon);
511 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
512 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
513 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
515 NSString *key([icon displayIdentifier]);
517 if (UIImage *image = [icon icon]) {
518 CGSize size = [image size];
519 if (size.width != 59 || size.height != 60) {
520 UIImage *cache($cacheForImage$(image));
521 [Cache_ setObject:cache forKey:key];
527 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
528 NSString *key([icon displayIdentifier]);
529 if (UIImage *image = [Cache_ objectForKey:key])
532 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
535 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
537 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
538 NSString *key([icon displayIdentifier]);
539 if (UIImage *image = [Cache_ objectForKey:key])
542 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
545 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
546 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
547 [self setBackgroundColor:[UIColor clearColor]];
548 for (UIView *child in [self subviews])
549 [child setBackgroundColor:[UIColor clearColor]];
553 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
554 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
555 [self setBackgroundColor:[UIColor clearColor]];
559 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
560 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
561 float inset([self edgeInset]);
562 [[UIColor clearColor] set];
563 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
564 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
567 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
568 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
569 if (NSString *path = $pathForIcon$([self application]))
570 return [UIImage imageWithContentsOfFile:path];
571 return _SBApplicationIcon$icon(self, sel);
574 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
576 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
577 if (IsWild_ && false) // XXX: delete this code, it should not be supported
578 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
579 return [UIImage imageWithContentsOfFile:path72];
580 if (NSString *path = $pathForIcon$([self application]))
581 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
583 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
584 width = [$SBIcon defaultIconImageSize].width;
587 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
590 return _SBApplicationIcon$generateIconImage$(self, sel, type);
593 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
595 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
596 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
597 return [UIImage imageWithContentsOfFile:path];
598 return _SBWidgetApplicationIcon$icon(self, sel);
601 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
603 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
604 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
605 return [UIImage imageWithContentsOfFile:path];
606 return _SBBookmarkIcon$icon(self, sel);
609 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
610 if (NSString *path = $pathForIcon$(self))
612 return _SBApplication$pathForIcon(self, sel);
615 static UIImage *CachedImageAtPath(NSString *path) {
616 path = [path stringByResolvingSymlinksInPath];
617 UIImage *image = [PathImages_ objectForKey:path];
619 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
620 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
622 image = [image autorelease];
623 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
627 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
628 NSBundle *bundle = [NSBundle mainBundle];
630 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
631 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
632 return CachedImageAtPath(path);
633 return __UIApplicationImageWithName(name);
636 #define WBDelegate(delegate) \
637 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
639 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
640 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
642 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
646 - (void) forwardInvocation:(NSInvocation*)inv { \
647 SEL sel = [inv selector]; \
648 if ([delegate respondsToSelector:sel]) \
649 [inv invokeWithTarget:delegate]; \
651 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
654 // %hook -[NSBundle pathForResource:ofType:] {{{
655 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
656 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
658 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
659 if (NSString *path = $pathForFile$inBundle$(file, self, false))
661 return MSOldCall(resource, type);
665 static struct WBStringDrawingState {
666 WBStringDrawingState *next_;
670 } *stringDrawingState_;
672 MSInstanceMessageHook4(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode, CGPoint, point, float, width, UIFont *, font, int, mode) {
673 WBStringDrawingState *state(stringDrawingState_);
675 return MSOldCall(point, width, font, mode);
677 if (--state->count_ == 0)
678 stringDrawingState_ = state->next_;
679 if (state->info_ == nil)
680 return MSOldCall(point, width, font, mode);
682 NSString *info([Info_ objectForKey:state->info_]);
684 return MSOldCall(point, width, font, mode);
686 NSString *base(state->base_ ?: @"");
687 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]];
691 MSInstanceMessageHook2(CGSize, NSString, drawAtPoint,withFont, CGPoint, point, UIFont *, font) {
692 WBStringDrawingState *state(stringDrawingState_);
694 return MSOldCall(point, font);
696 if (--state->count_ == 0)
697 stringDrawingState_ = state->next_;
698 if (state->info_ == nil)
699 return MSOldCall(point, font);
701 NSString *info([Info_ objectForKey:state->info_]);
703 return MSOldCall(point, font);
705 NSString *base(state->base_ ?: @"");
706 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]];
710 MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) {
711 WBStringDrawingState *state(stringDrawingState_);
713 return MSOldCall(font);
715 if (--state->count_ == 0)
716 stringDrawingState_ = state->next_;
717 if (state->info_ == nil)
718 return MSOldCall(font);
720 NSString *info([Info_ objectForKey:state->info_]);
722 return MSOldCall(font);
724 NSString *base(state->base_ ?: @"");
725 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info] forWidth:65535];
728 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
729 WBStringDrawingState badgeState = {NULL, 1, @""
733 stringDrawingState_ = &badgeState;
735 UIImage *image(MSOldCall(text));
737 stringDrawingState_ = NULL;
741 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
742 WBStringDrawingState dayState = {NULL, 2, @""
744 // XXX: this is only correct on an iPod dock
745 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
746 , @"CalendarIconDayStyle"};
748 WBStringDrawingState sizeState = {&dayState, 7, nil, nil};
750 WBStringDrawingState dateState = {&sizeState, 2, @""
752 , @"CalendarIconDateStyle"};
754 stringDrawingState_ = &dateState;
756 UIImage *image(MSOldCall(type));
758 stringDrawingState_ = NULL;
762 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
763 NSBundle *bundle([NSBundle mainBundle]);
765 CFLocaleRef locale(CFLocaleCopyCurrent());
766 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
769 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
771 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
772 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
773 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
774 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
778 CFRelease(formatter);
780 NSString *datestyle([@""
781 "font-family: Helvetica; "
782 "font-weight: bold; "
785 "" stringByAppendingString:(IsWild_
786 ? @"font-size: 54px; "
787 : @"font-size: 39px; "
790 NSString *daystyle([@""
791 "font-family: Helvetica; "
792 "font-weight: bold; "
794 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
795 "" stringByAppendingString:(IsWild_
796 ? @"font-size: 11px; "
797 : @"font-size: 9px; "
800 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
801 datestyle = [datestyle stringByAppendingString:style];
802 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
803 daystyle = [daystyle stringByAppendingString:style];
805 float width([self bounds].size.width);
807 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
808 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
810 unsigned base0(IsWild_ ? 89 : 70);
811 if ($GSFontGetUseLegacyFontMetrics())
813 unsigned base1(IsWild_ ? 18 : 16);
820 [(NSString *)date drawAtPoint:CGPointMake(
821 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
822 ) withStyle:datestyle];
824 [(NSString *)day drawAtPoint:CGPointMake(
825 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
826 ) withStyle:daystyle];
832 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
833 void $setBarStyle$_(NSString *name, int &style) {
835 NSLog(@"WB:Debug:%@Style:%d", name, style);
836 NSNumber *number = nil;
838 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
840 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
842 style = [number intValue];
844 NSLog(@"WB:Debug:%@Style=%d", name, style);
848 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
849 $setBarStyle$_(@"Toolbar", style);
850 return MSOldCall(style);
853 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
854 $setBarStyle$_(@"NavigationBar", style);
855 return MSOldCall(style);
859 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
860 [[self superview] setBackgroundColor:[UIColor clearColor]];
861 _SBButtonBar$didMoveToSuperview(self, sel);
864 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
865 [[self superview] setBackgroundColor:[UIColor clearColor]];
866 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
869 static NSArray *Wallpapers_;
870 static bool Papered_;
872 static bool SMSBackgrounded_;
873 static NSString *WallpaperFile_;
874 static UIImageView *WallpaperImage_;
875 static UIWebDocumentView *WallpaperPage_;
876 static NSURL *WallpaperURL_;
878 #define _release(object) \
879 do if (object != nil) { \
884 static UIImage *$getImage$(NSString *path) {
885 UIImage *image([UIImage imageWithContentsOfFile:path]);
887 unsigned scale($getScale$(path));
888 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
889 [image setScale:scale];
894 static UIImage *$getDefaultDesktopImage$() {
895 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
896 return $getImage$(path);
900 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
901 return $getDefaultDesktopImage$() ?: MSOldCall();
904 MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
905 return $getDefaultDesktopImage$() ?: MSOldCall();
908 MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
909 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
910 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
911 if (UIImage *image = $getDefaultDesktopImage$()) {
912 [self setImage:image];
922 // %hook -[SBUIController init] {{{
923 MSInstanceMessageHook0(id, SBUIController, init) {
928 NSString *paper($getTheme$(Wallpapers_));
930 paper = [paper stringByDeletingLastPathComponent];
934 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
935 char *machine = new char[size];
937 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
938 perror("sysctlbyname(\"hw.machine\", ?)");
943 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
947 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
950 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
951 if (&_wallpaperView != NULL) {
952 [_wallpaperView removeFromSuperview];
953 [_wallpaperView release];
954 _wallpaperView = nil;
958 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
959 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
962 if (&_contentLayer != NULL)
963 player = &_contentLayer;
964 else if (&_contentView != NULL)
965 player = &_contentView;
968 UIView *layer(player == NULL ? nil : *player);
970 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
971 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
972 [window setContentView:content];
974 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
975 [window setBackgroundColor:[_window backgroundColor]];
976 [_window setBackgroundColor:[UIColor clearColor]];
978 [window setLevel:-1000];
979 [window setHidden:NO];
981 /*if (player != NULL)
984 [content setBackgroundColor:[layer backgroundColor]];
985 [layer setBackgroundColor:[UIColor clearColor]];
988 if (!SummerBoard_ || !IsWild_)
991 CGRect bounds([content bounds]);
992 bounds.origin.y = -30;
993 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
994 [content addSubview:indirect];
995 [indirect zoomToScale:2.4];
998 _release(WallpaperFile_);
999 _release(WallpaperImage_);
1000 _release(WallpaperPage_);
1001 _release(WallpaperURL_);
1004 NSArray *themes([NSArray arrayWithObject:paper]);
1006 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1010 static AVController *controller_(nil);
1011 if (controller_ == nil) {
1012 AVQueue *queue([AVQueue avQueue]);
1013 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1016 AVQueue *queue([controller_ queue]);
1018 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1019 [controller_ setLayer:[video _layer]];
1021 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1022 [queue appendItem:item error:&error];
1024 [controller_ play:&error];
1025 #elif UseMPMoviePlayerController
1026 NSURL *url([NSURL fileURLWithPath:path]);
1027 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1028 controller.movieControlMode = MPMovieControlModeHidden;
1031 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1032 [video setMovieWithPath:path];
1033 [video setRepeatMode:1];
1034 [video setRepeatGap:-1];
1035 [video playFromBeginning];;
1038 [indirect addSubview:video];
1041 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1042 if (UIImage *image = $getImage$(path)) {
1043 WallpaperFile_ = [path retain];
1044 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1045 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1046 [WallpaperImage_ setAlpha:[number floatValue]];
1047 [indirect addSubview:WallpaperImage_];
1051 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1052 CGRect bounds = [indirect bounds];
1054 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1055 [view setAutoresizes:true];
1057 WallpaperPage_ = [view retain];
1058 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1060 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1062 [view setBackgroundColor:[UIColor clearColor]];
1063 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1064 [view setDrawsBackground:NO];
1065 [[view webView] setDrawsBackground:NO];
1067 [indirect addSubview:view];
1071 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1072 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1073 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1074 if ([Manager_ fileExistsAtPath:html]) {
1075 CGRect bounds = [indirect bounds];
1077 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1078 [view setAutoresizes:true];
1080 NSURL *url = [NSURL fileURLWithPath:html];
1081 [view loadRequest:[NSURLRequest requestWithURL:url]];
1083 [view setBackgroundColor:[UIColor clearColor]];
1084 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1085 [view setDrawsBackground:NO];
1086 [[view webView] setDrawsBackground:NO];
1088 [indirect addSubview:view];
1096 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1097 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1098 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1100 if (path != nil && _backgroundView != nil)
1103 _SBAwayView$updateDesktopImage$(self, sel, image);
1106 CGRect bounds = [self bounds];
1108 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1109 [view setAutoresizes:true];
1111 if (WallpaperPage_ != nil)
1112 [WallpaperPage_ release];
1113 WallpaperPage_ = [view retain];
1115 if (WallpaperURL_ != nil)
1116 [WallpaperURL_ release];
1117 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1119 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1121 [[view webView] setDrawsBackground:false];
1122 [view setBackgroundColor:[UIColor clearColor]];
1124 [self insertSubview:view aboveSubview:_backgroundView];
1128 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1129 extern "C" CGColorRef CGGStateGetFillColor(void *);
1130 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1131 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1133 /* WBTimeLabel {{{ */
1134 @interface WBTimeLabel : NSProxy {
1136 _transient SBStatusBarTimeView *view_;
1139 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1143 @implementation WBTimeLabel
1150 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1151 time_ = [time retain];
1156 - (NSString *) description {
1162 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1163 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1164 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1166 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1167 "font-family: Helvetica; "
1168 "font-weight: bold; "
1171 "%@", _mode ? @"white" : @"black", custom]];
1176 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1181 /* WBBadgeLabel {{{ */
1182 @interface WBBadgeLabel : NSProxy {
1186 - (id) initWithBadge:(NSString *)badge;
1187 - (NSString *) description;
1191 @implementation WBBadgeLabel
1198 - (id) initWithBadge:(NSString *)badge {
1199 badge_ = [badge retain];
1203 - (NSString *) description {
1204 return [badge_ description];
1209 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1210 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1211 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1212 "font-family: Helvetica; "
1213 "font-weight: bold; "
1221 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1228 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1229 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1230 alpha = [number floatValue];
1231 return MSOldCall(alpha);
1234 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1235 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1236 alpha = [number floatValue];
1237 return MSOldCall(alpha);
1240 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1241 if ((self = MSOldCall()) != nil) {
1242 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1243 // XXX: note: this is overridden above, which is silly
1244 float alpha([number floatValue]);
1245 [self setIconImageAlpha:alpha];
1246 [self setIconLabelAlpha:alpha];
1251 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1252 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1253 alpha = [number floatValue];
1254 return MSOldCall(alpha);
1258 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1259 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1260 id &_badge(MSHookIvar<id>(self, "_badge"));
1262 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1267 void SBStatusBarController$setStatusBarMode(int &mode) {
1269 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1270 if (mode < 100) // 104:hidden 105:glowing
1271 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1272 mode = [number intValue];
1275 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1276 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1277 SBStatusBarController$setStatusBarMode(mode);
1278 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1281 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1282 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1283 SBStatusBarController$setStatusBarMode(mode);
1284 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1287 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int fenceID, int animation, double startTime) {
1288 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1289 SBStatusBarController$setStatusBarMode(mode);
1290 //NSLog(@"mode=%u", mode);
1291 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1294 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1295 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1296 mode = [number intValue];
1297 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1300 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1301 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1303 NSLog(@"operatorNameStyle= %@", style);
1304 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1305 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1309 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1311 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1312 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1315 // XXX: replace this with [SBStatusBarTimeView tile]
1316 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1317 id &_time(MSHookIvar<id>(self, "_time"));
1318 if (_time != nil && [_time class] != [WBTimeLabel class])
1319 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1320 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1323 @interface UIView (WinterBoard)
1324 - (bool) wb$isWBImageView;
1325 - (void) wb$logHierarchy;
1326 - (void) wb$setBackgroundColor:(UIColor *)color;
1329 @implementation UIView (WinterBoard)
1331 - (bool) wb$isWBImageView {
1335 - (void) wb$logHierarchy {
1336 WBLogHierarchy(self);
1339 - (void) wb$setBackgroundColor:(UIColor *)color {
1340 [self setBackgroundColor:color];
1341 for (UIView *child in [self subviews])
1342 [child wb$setBackgroundColor:color];
1347 @interface WBImageView : UIImageView {
1350 - (bool) wb$isWBImageView;
1351 - (void) wb$updateFrame;
1354 @implementation WBImageView
1356 - (bool) wb$isWBImageView {
1360 - (void) wb$updateFrame {
1361 CGRect frame([self frame]);
1364 for (UIView *view(self); ; ) {
1365 view = [view superview];
1368 frame.origin.y -= [view frame].origin.y;
1371 [self setFrame:frame];
1376 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1377 NSArray *subviews([self subviews]);
1378 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1379 if (view != nil && [view wb$isWBImageView])
1380 [view wb$updateFrame];
1381 _SBIconList$setFrame$(self, sel, frame);
1384 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1385 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1386 NSArray *lists([_iconModel iconLists]);
1388 for (unsigned i(0), e([lists count]); i != e; ++i)
1389 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]])) {
1390 SBIconList *list([lists objectAtIndex:i]);
1391 NSArray *subviews([list subviews]);
1393 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1394 if (view == nil || ![view wb$isWBImageView]) {
1395 view = [[[WBImageView alloc] init] autorelease];
1396 [list insertSubview:view atIndex:0];
1399 UIImage *image([UIImage imageWithContentsOfFile:path]);
1401 CGRect frame([view frame]);
1402 frame.size = [image size];
1403 [view setFrame:frame];
1405 [view setImage:image];
1406 [view wb$updateFrame];
1409 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1412 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1413 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1415 [self setClipsToBounds:NO];
1419 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1420 static bool gssc(false);
1422 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1423 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1426 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1427 [Info_ setObject:[NSNumber numberWithBool:(
1429 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1430 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1431 )] forKey:@"UndockedIconLabels"];
1434 id &_label(MSHookIvar<id>(self, "_label"));
1435 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1438 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1439 [_label setInDock:docked];
1441 _SBIconLabel$setInDock$(self, sel, docked);
1442 [self setNeedsDisplay];
1445 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1446 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1449 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1450 _SBDockIconListView$setFrame$(self, sel, frame);
1453 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1454 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1455 NSString *identifier = [self bundleIdentifier];
1456 NSLocale *locale = [NSLocale currentLocale];
1457 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1459 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1460 NSString *file = table == nil ? @"Localizable" : table;
1461 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1462 NSDictionary *strings;
1463 if ((strings = [Strings_ objectForKey:name]) != nil) {
1464 if (static_cast<id>(strings) != [NSNull null]) strings:
1465 if (NSString *value = [strings objectForKey:key])
1467 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1470 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1471 [Strings_ setObject:[strings autorelease] forKey:name];
1475 [Strings_ setObject:[NSNull null] forKey:name];
1476 return MSOldCall(key, value, table);
1479 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1480 MSClassHook(WebCoreFrameBridge)
1482 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1485 void **core(reinterpret_cast<void **>([node _node]));
1486 if (core == NULL || core[6] == NULL)
1488 return MSOldCall(node, width);
1492 MSInstanceMessageHook1(void, SBIconLabel, drawRect, CGRect, rect) {
1493 CGRect bounds = [self bounds];
1495 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1498 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1499 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1501 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1503 NSString *style = [NSString stringWithFormat:@""
1504 "font-family: Helvetica; "
1505 "font-weight: bold; "
1507 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1508 ? @"font-size: 12px; "
1509 : @"font-size: 11px; "
1513 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1515 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1517 bool ellipsis(false);
1518 float max = [self frame].size.width - 11, width;
1520 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
1523 size_t length([label length]);
1524 float spacing((width - max) / (length - 1));
1526 if (spacing > 1.25) {
1528 label = [label substringToIndex:(length - 1)];
1532 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
1536 label = [label stringByAppendingString:@"..."];
1538 if (NSString *custom = [Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")])
1539 style = [style stringByAppendingString:custom];
1541 CGSize size = [label sizeWithStyle:style forWidth:bounds.size.width];
1542 [label drawAtPoint:CGPointMake((bounds.size.width - size.width) / 2, 0) withStyle:style];
1546 MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1547 if ((self = MSOldCall(frame, delegate)) != nil) {
1548 [self setBackgroundColor:[UIColor clearColor]];
1552 MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1553 return SMSBackgrounded_ ? NO : MSOldCall();
1556 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1557 [self wb$setBackgroundColor:[UIColor clearColor]];
1561 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1563 [balloon setBackgroundColor:[UIColor clearColor]];
1566 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1567 MSOldCall([UIColor clearColor]);
1568 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1572 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1573 if ((self = MSOldCall(style, reuse)) != nil) {
1574 [self setBackgroundColor:[UIColor clearColor]];
1575 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1580 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1581 if ((self = MSOldCall(style, reuse)) != nil) {
1582 [self setBackgroundColor:[UIColor clearColor]];
1583 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1587 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1588 if ((self = MSOldCall(style, reuse)) != nil) {
1589 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1590 [_label setBackgroundColor:[UIColor clearColor]];
1594 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1595 MSOldCall(UITableViewCellSeparatorStyleNone);
1598 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1599 if ((self = MSOldCall(frame, style)) != nil) {
1600 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1604 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1607 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1608 if (UIImage *image = $getImage$(path)) {
1609 SMSBackgrounded_ = true;
1611 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1612 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1614 if (&_transcriptTable != NULL)
1615 table = _transcriptTable;
1616 else if (&_transcriptLayer != NULL)
1617 table = _transcriptLayer;
1621 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1622 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1625 [placard insertSubview:background atIndex:0];
1627 [table setBackgroundColor:[UIColor clearColor]];
1628 [placard insertSubview:background belowSubview:table];
1634 // %hook _UIImageWithName() {{{
1635 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1637 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1644 if (_UIPackedImageTableGetIdentifierForName != NULL)
1645 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1646 else if (_UISharedImageNameGetIdentifier != NULL) {
1647 identifier = _UISharedImageNameGetIdentifier(name);
1648 packed = identifier != -1;
1655 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1658 return __UIImageWithName(name);
1660 NSNumber *key([NSNumber numberWithInt:identifier]);
1661 UIImage *image([UIImages_ objectForKey:key]);
1663 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1664 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1665 image = $getImage$(path);
1666 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1670 image = __UIImageWithName(name);
1673 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1674 if (![Manager_ fileExistsAtPath:path])
1675 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1682 // %hook _UIImageWithNameInDomain() {{{
1683 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1684 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1685 UIImage *image([PathImages_ objectForKey:key]);
1687 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1689 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1690 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1691 image = $getImage$(path);
1692 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1693 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1697 // %hook GSFontCreateWithName() {{{
1698 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1700 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1701 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1702 name = [font UTF8String];
1703 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1704 // size *= [scale floatValue];
1705 return _GSFontCreateWithName(name, traits, size);
1709 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1710 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1712 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1714 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1716 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1717 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1719 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1722 NSString *path = [NSString stringWithUTF8String:a1];
1723 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1724 NSString *file = [path substringFromIndex:31];
1725 for (NSString *theme in Themes_) {
1726 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1727 if ([Manager_ fileExistsAtPath:path]) {
1728 strcpy(a1, [path UTF8String]);
1737 static void ChangeWallpaper(
1738 CFNotificationCenterRef center,
1742 CFDictionaryRef info
1745 NSLog(@"WB:Debug:ChangeWallpaper!");
1748 if (WallpaperFile_ != nil) {
1749 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1751 image = [image autorelease];
1754 if (WallpaperImage_ != nil)
1755 [WallpaperImage_ setImage:image];
1756 if (WallpaperPage_ != nil)
1757 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1761 #define WBRename(name, sel, imp) \
1762 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
1764 template <typename Type_>
1765 static void msset(Type_ &function, MSImageRef image, const char *name) {
1766 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1769 template <typename Type_>
1770 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1771 struct nlist &name(nl[index]);
1772 uintptr_t value(name.n_value);
1773 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1774 value |= 0x00000001;
1775 function = reinterpret_cast<Type_>(value);
1778 template <typename Type_>
1779 static void dlset(Type_ &function, const char *name) {
1780 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1783 // %hook CGImageReadCreateWithFile() {{{
1784 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1786 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1787 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1788 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1794 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
1795 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1796 if (style == nil || [style length] == 0)
1797 style = @"font-family: Helvetica; font-size: 12px";
1798 return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
1801 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
1802 if (style == nil || [style length] == 0)
1803 style = @"font-family: Helvetica; font-size: 12px";
1804 return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width];
1807 static void SBInitialize() {
1808 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
1809 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
1812 WBRename(SBApplication, pathForIcon, pathForIcon);
1813 WBRename(SBApplicationIcon, icon, icon);
1814 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1817 WBRename(SBBookmarkIcon, icon, icon);
1818 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1819 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1820 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1821 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
1823 WBRename(SBWidgetApplicationIcon, icon, icon);
1825 WBRename(SBDockIconListView, setFrame:, setFrame$);
1826 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
1828 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
1829 WBRename(SBIconLabel, setInDock:, setInDock$);
1831 WBRename(SBIconList, setFrame:, setFrame$);
1833 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
1834 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
1835 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
1836 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
1838 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
1839 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
1840 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
1842 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
1844 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
1845 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
1846 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
1847 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
1848 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
1849 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
1850 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
1851 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
1852 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
1855 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
1859 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1861 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
1862 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
1864 Manager_ = [[NSFileManager defaultManager] retain];
1865 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
1867 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
1869 // Load Settings.plist {{{
1870 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
1871 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
1872 SummerBoard_ = [value boolValue];
1873 if (NSNumber *value = [settings objectForKey:@"Debug"])
1874 Debug_ = [value boolValue];
1875 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
1876 UIDebug_ = [value boolValue];
1878 NSArray *themes([settings objectForKey:@"Themes"]);
1880 if (NSString *theme = [settings objectForKey:@"Theme"])
1881 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
1883 [NSNumber numberWithBool:true], @"Active",
1887 for (NSDictionary *theme in themes) {
1888 NSNumber *active([theme objectForKey:@"Active"]);
1889 if (![active boolValue])
1892 NSString *name([theme objectForKey:@"Name"]);
1896 NSString *theme(nil);
1898 #define testForTheme(format...) \
1899 if (theme == nil) { \
1900 NSString *path = [NSString stringWithFormat:format]; \
1901 if ([Manager_ fileExistsAtPath:path]) { \
1902 [Themes_ addObject:path]; \
1907 testForTheme(@"/Library/Themes/%@.theme", name)
1908 testForTheme(@"/Library/Themes/%@", name)
1909 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
1914 // Merge Info.plist {{{
1915 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1917 for (NSString *theme in Themes_)
1918 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
1919 for (NSString *key in [info allKeys])
1920 if ([Info_ objectForKey:key] == nil)
1921 [Info_ setObject:[info objectForKey:key] forKey:key];
1925 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
1926 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
1927 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
1930 // GraphicsServices {{{
1932 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
1936 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
1937 void *(*CGImageReadCreateWithFile)(NSString *, int);
1938 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
1939 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
1944 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
1945 Papered_ = $getTheme$(Wallpapers_) != nil;
1946 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
1948 CFNotificationCenterAddObserver(
1949 CFNotificationCenterGetDarwinNotifyCenter(),
1950 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
1953 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
1954 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
1955 if (MediaPlayer != nil)
1958 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
1959 $MPVideoView = objc_getClass("MPVideoView");
1966 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
1968 memset(nl, 0, sizeof(nl));
1969 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
1970 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
1971 nl[2].n_un.n_name = (char *) "__UIKitBundle";
1972 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
1973 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
1976 nlset(_UIApplicationImageWithName, nl, 0);
1977 nlset(_UIImageWithNameInDomain, nl, 1);
1978 nlset(_UIKitBundle, nl, 2);
1979 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
1980 nlset(_UISharedImageNameGetIdentifier, nl, 4);
1982 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
1983 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
1984 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
1988 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
1989 NSError *error(nil);
1990 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
1991 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
1993 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);