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]];
328 NSString *base([folder stringByDeletingPathExtension]);
329 if ([base hasSuffix:@"~iphone"])
330 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 7)], [folder pathExtension], file]];
333 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
335 #define remapResourceName(oldname, newname) \
336 else if ([file isEqualToString:(oldname)]) \
337 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
339 bool summer(SpringBoard_ && SummerBoard_);
341 if (identifier == nil);
342 else if ([identifier isEqualToString:@"com.apple.chatkit"])
343 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
344 else if ([identifier isEqualToString:@"com.apple.calculator"])
345 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
347 remapResourceName(@"FSO_BG.png", @"StatusBar")
348 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
349 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
351 if (NSString *path = $getTheme$($useScale$(names, ui)))
358 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
359 NSString *identifier = [self bundleIdentifier];
360 NSString *path = [self path];
361 NSString *folder = [path lastPathComponent];
362 NSString *dname = [self displayName];
363 NSString *didentifier = [self displayIdentifier];
366 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
368 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
370 /* XXX: I might need to keep this for backwards compatibility
371 if (identifier != nil)
372 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
374 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
376 #define testForIcon(Name) \
377 if (NSString *name = Name) \
378 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
380 if (![didentifier isEqualToString:identifier])
381 testForIcon(didentifier);
383 testForIcon(identifier);
386 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
389 if (didentifier != nil) {
390 testForIcon([English_ objectForKey:didentifier]);
392 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
393 if ([parts count] != 1)
394 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
395 testForIcon([english objectForKey:[parts lastObject]]);
398 if (NSString *path = $getTheme$(names))
404 // -[NSBundle wb$bundleWithFile] {{{
405 @interface NSBundle (WinterBoard)
406 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
409 @implementation NSBundle (WinterBoard)
411 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
412 path = [path stringByDeletingLastPathComponent];
413 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
416 NSBundle *bundle([Bundles_ objectForKey:path]);
417 if (reinterpret_cast<id>(bundle) == [NSNull null])
419 else if (bundle == nil) {
420 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
421 bundle = [NSBundle bundleWithPath:path];
423 bundle = [NSBundle wb$bundleWithFile:path];
425 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
426 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
434 // -[NSString wb$themedPath] {{{
435 @interface NSString (WinterBoard)
436 - (NSString *) wb$themedPath;
439 @implementation NSString (WinterBoard)
441 - (NSString *) wb$themedPath {
442 if ([self hasPrefix:@"/Library/Themes/"])
446 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
448 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
449 NSString *file([self stringByResolvingSymlinksInPath]);
450 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
451 if ([file hasPrefix:prefix]) {
452 NSUInteger length([prefix length]);
453 if (length != [file length])
454 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
465 void WBLogRect(const char *tag, struct CGRect rect) {
466 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
469 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
470 CGRect frame([view frame]);
471 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]);
473 for (UIView *child in [view subviews])
474 WBLogHierarchy(child, index++, indent + 1);
477 UIImage *$cacheForImage$(UIImage *image) {
478 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
479 CGRect rect = {CGPointMake(1, 1), [image size]};
480 CGSize size = {rect.size.width + 2, rect.size.height + 2};
482 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
483 CGColorSpaceRelease(space);
485 CGContextDrawImage(context, rect, [image CGImage]);
486 CGImageRef ref(CGBitmapContextCreateImage(context));
487 CGContextRelease(context);
489 UIImage *cache([UIImage imageWithCGImage:ref]);
495 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
496 //if ([name isEqualToString:@"icons"]) return nil;
497 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
500 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
501 NSString *key([icon displayIdentifier]);
503 if (UIImage *image = [icon icon]) {
504 CGSize size = [image size];
505 if (size.width != 59 || size.height != 60) {
506 UIImage *cache($cacheForImage$(image));
507 [Cache_ setObject:cache forKey:key];
512 _SBIconModel$cacheImageForIcon$(self, sel, icon);
515 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
516 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
517 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
519 NSString *key([icon displayIdentifier]);
521 if (UIImage *image = [icon icon]) {
522 CGSize size = [image size];
523 if (size.width != 59 || size.height != 60) {
524 UIImage *cache($cacheForImage$(image));
525 [Cache_ setObject:cache forKey:key];
531 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
532 NSString *key([icon displayIdentifier]);
533 if (UIImage *image = [Cache_ objectForKey:key])
536 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
539 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
541 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
542 NSString *key([icon displayIdentifier]);
543 if (UIImage *image = [Cache_ objectForKey:key])
546 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
549 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
550 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
551 [self setBackgroundColor:[UIColor clearColor]];
552 for (UIView *child in [self subviews])
553 [child setBackgroundColor:[UIColor clearColor]];
557 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
558 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
559 [self setBackgroundColor:[UIColor clearColor]];
563 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
564 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
565 float inset([self edgeInset]);
566 [[UIColor clearColor] set];
567 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
568 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
571 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
572 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
573 if (NSString *path = $pathForIcon$([self application]))
574 return [UIImage imageWithContentsOfFile:path];
575 return _SBApplicationIcon$icon(self, sel);
578 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
580 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
581 if (IsWild_ && false) // XXX: delete this code, it should not be supported
582 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
583 return [UIImage imageWithContentsOfFile:path72];
584 if (NSString *path = $pathForIcon$([self application]))
585 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
587 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
588 width = [$SBIcon defaultIconImageSize].width;
591 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
594 return _SBApplicationIcon$generateIconImage$(self, sel, type);
597 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
599 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
600 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
601 return [UIImage imageWithContentsOfFile:path];
602 return _SBWidgetApplicationIcon$icon(self, sel);
605 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
607 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
608 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
609 return [UIImage imageWithContentsOfFile:path];
610 return _SBBookmarkIcon$icon(self, sel);
613 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
614 if (NSString *path = $pathForIcon$(self))
616 return _SBApplication$pathForIcon(self, sel);
619 static UIImage *CachedImageAtPath(NSString *path) {
620 path = [path stringByResolvingSymlinksInPath];
621 UIImage *image = [PathImages_ objectForKey:path];
623 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
624 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
626 image = [image autorelease];
627 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
631 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
632 NSBundle *bundle = [NSBundle mainBundle];
634 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
635 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
636 return CachedImageAtPath(path);
637 return __UIApplicationImageWithName(name);
640 #define WBDelegate(delegate) \
641 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
643 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
644 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
646 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
650 - (void) forwardInvocation:(NSInvocation*)inv { \
651 SEL sel = [inv selector]; \
652 if ([delegate respondsToSelector:sel]) \
653 [inv invokeWithTarget:delegate]; \
655 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
658 // %hook -[NSBundle pathForResource:ofType:] {{{
659 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
660 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
662 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
663 if (NSString *path = $pathForFile$inBundle$(file, self, false))
665 return MSOldCall(resource, type);
669 static struct WBStringDrawingState {
670 WBStringDrawingState *next_;
674 } *stringDrawingState_;
676 MSInstanceMessageHook4(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode, CGPoint, point, float, width, UIFont *, font, int, mode) {
677 WBStringDrawingState *state(stringDrawingState_);
679 return MSOldCall(point, width, font, mode);
681 if (--state->count_ == 0)
682 stringDrawingState_ = state->next_;
683 if (state->info_ == nil)
684 return MSOldCall(point, width, font, mode);
686 NSString *info([Info_ objectForKey:state->info_]);
688 return MSOldCall(point, width, font, mode);
690 NSString *base(state->base_ ?: @"");
691 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]];
695 MSInstanceMessageHook2(CGSize, NSString, drawAtPoint,withFont, CGPoint, point, UIFont *, font) {
696 WBStringDrawingState *state(stringDrawingState_);
698 return MSOldCall(point, font);
700 if (--state->count_ == 0)
701 stringDrawingState_ = state->next_;
702 if (state->info_ == nil)
703 return MSOldCall(point, font);
705 NSString *info([Info_ objectForKey:state->info_]);
707 return MSOldCall(point, font);
709 NSString *base(state->base_ ?: @"");
710 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]];
714 MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) {
715 WBStringDrawingState *state(stringDrawingState_);
717 return MSOldCall(font);
719 if (--state->count_ == 0)
720 stringDrawingState_ = state->next_;
721 if (state->info_ == nil)
722 return MSOldCall(font);
724 NSString *info([Info_ objectForKey:state->info_]);
726 return MSOldCall(font);
728 NSString *base(state->base_ ?: @"");
729 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info] forWidth:65535];
732 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
733 WBStringDrawingState badgeState = {NULL, 1, @""
737 stringDrawingState_ = &badgeState;
739 UIImage *image(MSOldCall(text));
741 stringDrawingState_ = NULL;
745 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
746 WBStringDrawingState dayState = {NULL, 2, @""
748 // XXX: this is only correct on an iPod dock
749 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
750 , @"CalendarIconDayStyle"};
752 WBStringDrawingState sizeState = {&dayState, 7, nil, nil};
754 WBStringDrawingState dateState = {&sizeState, 2, @""
756 , @"CalendarIconDateStyle"};
758 stringDrawingState_ = &dateState;
760 UIImage *image(MSOldCall(type));
762 stringDrawingState_ = NULL;
766 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
767 NSBundle *bundle([NSBundle mainBundle]);
769 CFLocaleRef locale(CFLocaleCopyCurrent());
770 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
773 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
775 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
776 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
777 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
778 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
782 CFRelease(formatter);
784 NSString *datestyle([@""
785 "font-family: Helvetica; "
786 "font-weight: bold; "
789 "" stringByAppendingString:(IsWild_
790 ? @"font-size: 54px; "
791 : @"font-size: 39px; "
794 NSString *daystyle([@""
795 "font-family: Helvetica; "
796 "font-weight: bold; "
798 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
799 "" stringByAppendingString:(IsWild_
800 ? @"font-size: 11px; "
801 : @"font-size: 9px; "
804 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
805 datestyle = [datestyle stringByAppendingString:style];
806 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
807 daystyle = [daystyle stringByAppendingString:style];
809 float width([self bounds].size.width);
811 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
812 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
814 unsigned base0(IsWild_ ? 89 : 70);
815 if ($GSFontGetUseLegacyFontMetrics())
817 unsigned base1(IsWild_ ? 18 : 16);
824 [(NSString *)date drawAtPoint:CGPointMake(
825 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
826 ) withStyle:datestyle];
828 [(NSString *)day drawAtPoint:CGPointMake(
829 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
830 ) withStyle:daystyle];
836 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
837 void $setBarStyle$_(NSString *name, int &style) {
839 NSLog(@"WB:Debug:%@Style:%d", name, style);
840 NSNumber *number = nil;
842 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
844 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
846 style = [number intValue];
848 NSLog(@"WB:Debug:%@Style=%d", name, style);
852 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
853 $setBarStyle$_(@"Toolbar", style);
854 return MSOldCall(style);
857 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
858 $setBarStyle$_(@"NavigationBar", style);
859 return MSOldCall(style);
863 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
864 [[self superview] setBackgroundColor:[UIColor clearColor]];
865 _SBButtonBar$didMoveToSuperview(self, sel);
868 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
869 [[self superview] setBackgroundColor:[UIColor clearColor]];
870 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
873 static NSArray *Wallpapers_;
874 static bool Papered_;
876 static bool SMSBackgrounded_;
877 static NSString *WallpaperFile_;
878 static UIImageView *WallpaperImage_;
879 static UIWebDocumentView *WallpaperPage_;
880 static NSURL *WallpaperURL_;
882 #define _release(object) \
883 do if (object != nil) { \
888 static UIImage *$getImage$(NSString *path) {
889 UIImage *image([UIImage imageWithContentsOfFile:path]);
891 unsigned scale($getScale$(path));
892 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
893 [image setScale:scale];
898 static UIImage *$getDefaultDesktopImage$() {
899 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
900 return $getImage$(path);
904 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
905 return $getDefaultDesktopImage$() ?: MSOldCall();
908 MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
909 return $getDefaultDesktopImage$() ?: MSOldCall();
912 MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
913 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
914 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
915 if (UIImage *image = $getDefaultDesktopImage$()) {
916 [self setImage:image];
926 // %hook -[SBUIController init] {{{
927 MSInstanceMessageHook0(id, SBUIController, init) {
932 NSString *paper($getTheme$(Wallpapers_));
934 paper = [paper stringByDeletingLastPathComponent];
938 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
939 char *machine = new char[size];
941 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
942 perror("sysctlbyname(\"hw.machine\", ?)");
947 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
951 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
954 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
955 if (&_wallpaperView != NULL) {
956 [_wallpaperView removeFromSuperview];
957 [_wallpaperView release];
958 _wallpaperView = nil;
962 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
963 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
966 if (&_contentLayer != NULL)
967 player = &_contentLayer;
968 else if (&_contentView != NULL)
969 player = &_contentView;
972 UIView *layer(player == NULL ? nil : *player);
974 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
975 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
976 [window setContentView:content];
978 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
979 [window setBackgroundColor:[_window backgroundColor]];
980 [_window setBackgroundColor:[UIColor clearColor]];
982 [window setLevel:-1000];
983 [window setHidden:NO];
985 /*if (player != NULL)
988 [content setBackgroundColor:[layer backgroundColor]];
989 [layer setBackgroundColor:[UIColor clearColor]];
992 if (!SummerBoard_ || !IsWild_)
995 CGRect bounds([content bounds]);
996 bounds.origin.y = -30;
997 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
998 [content addSubview:indirect];
999 [indirect zoomToScale:2.4];
1002 _release(WallpaperFile_);
1003 _release(WallpaperImage_);
1004 _release(WallpaperPage_);
1005 _release(WallpaperURL_);
1008 NSArray *themes([NSArray arrayWithObject:paper]);
1010 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1014 static AVController *controller_(nil);
1015 if (controller_ == nil) {
1016 AVQueue *queue([AVQueue avQueue]);
1017 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1020 AVQueue *queue([controller_ queue]);
1022 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1023 [controller_ setLayer:[video _layer]];
1025 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1026 [queue appendItem:item error:&error];
1028 [controller_ play:&error];
1029 #elif UseMPMoviePlayerController
1030 NSURL *url([NSURL fileURLWithPath:path]);
1031 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1032 controller.movieControlMode = MPMovieControlModeHidden;
1035 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1036 [video setMovieWithPath:path];
1037 [video setRepeatMode:1];
1038 [video setRepeatGap:-1];
1039 [video playFromBeginning];;
1042 [indirect addSubview:video];
1045 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1046 if (UIImage *image = $getImage$(path)) {
1047 WallpaperFile_ = [path retain];
1048 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1049 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1050 [WallpaperImage_ setAlpha:[number floatValue]];
1051 [indirect addSubview:WallpaperImage_];
1055 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1056 CGRect bounds = [indirect bounds];
1058 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1059 [view setAutoresizes:true];
1061 WallpaperPage_ = [view retain];
1062 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1064 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1066 [view setBackgroundColor:[UIColor clearColor]];
1067 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1068 [view setDrawsBackground:NO];
1069 [[view webView] setDrawsBackground:NO];
1071 [indirect addSubview:view];
1075 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1076 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1077 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1078 if ([Manager_ fileExistsAtPath:html]) {
1079 CGRect bounds = [indirect bounds];
1081 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1082 [view setAutoresizes:true];
1084 NSURL *url = [NSURL fileURLWithPath:html];
1085 [view loadRequest:[NSURLRequest requestWithURL:url]];
1087 [view setBackgroundColor:[UIColor clearColor]];
1088 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1089 [view setDrawsBackground:NO];
1090 [[view webView] setDrawsBackground:NO];
1092 [indirect addSubview:view];
1100 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1101 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1102 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1104 if (path != nil && _backgroundView != nil)
1107 _SBAwayView$updateDesktopImage$(self, sel, image);
1110 CGRect bounds = [self bounds];
1112 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1113 [view setAutoresizes:true];
1115 if (WallpaperPage_ != nil)
1116 [WallpaperPage_ release];
1117 WallpaperPage_ = [view retain];
1119 if (WallpaperURL_ != nil)
1120 [WallpaperURL_ release];
1121 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1123 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1125 [[view webView] setDrawsBackground:false];
1126 [view setBackgroundColor:[UIColor clearColor]];
1128 [self insertSubview:view aboveSubview:_backgroundView];
1132 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1133 extern "C" CGColorRef CGGStateGetFillColor(void *);
1134 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1135 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1137 /* WBTimeLabel {{{ */
1138 @interface WBTimeLabel : NSProxy {
1140 _transient SBStatusBarTimeView *view_;
1143 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1147 @implementation WBTimeLabel
1154 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1155 time_ = [time retain];
1160 - (NSString *) description {
1166 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1167 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1168 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1170 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1171 "font-family: Helvetica; "
1172 "font-weight: bold; "
1175 "%@", _mode ? @"white" : @"black", custom]];
1180 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1185 /* WBBadgeLabel {{{ */
1186 @interface WBBadgeLabel : NSProxy {
1190 - (id) initWithBadge:(NSString *)badge;
1191 - (NSString *) description;
1195 @implementation WBBadgeLabel
1202 - (id) initWithBadge:(NSString *)badge {
1203 badge_ = [badge retain];
1207 - (NSString *) description {
1208 return [badge_ description];
1213 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1214 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1215 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1216 "font-family: Helvetica; "
1217 "font-weight: bold; "
1225 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1232 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1233 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1234 alpha = [number floatValue];
1235 return MSOldCall(alpha);
1238 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1239 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1240 alpha = [number floatValue];
1241 return MSOldCall(alpha);
1244 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1245 if ((self = MSOldCall()) != nil) {
1246 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1247 // XXX: note: this is overridden above, which is silly
1248 float alpha([number floatValue]);
1249 [self setIconImageAlpha:alpha];
1250 [self setIconLabelAlpha:alpha];
1255 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1256 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1257 alpha = [number floatValue];
1258 return MSOldCall(alpha);
1262 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1263 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1264 id &_badge(MSHookIvar<id>(self, "_badge"));
1266 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1271 void SBStatusBarController$setStatusBarMode(int &mode) {
1273 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1274 if (mode < 100) // 104:hidden 105:glowing
1275 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1276 mode = [number intValue];
1279 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1280 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1281 SBStatusBarController$setStatusBarMode(mode);
1282 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1285 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1286 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1287 SBStatusBarController$setStatusBarMode(mode);
1288 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1291 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) {
1292 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1293 SBStatusBarController$setStatusBarMode(mode);
1294 //NSLog(@"mode=%u", mode);
1295 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1298 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1299 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1300 mode = [number intValue];
1301 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1304 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1305 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1307 NSLog(@"operatorNameStyle= %@", style);
1308 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1309 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1313 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1315 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1316 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1319 // XXX: replace this with [SBStatusBarTimeView tile]
1320 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1321 id &_time(MSHookIvar<id>(self, "_time"));
1322 if (_time != nil && [_time class] != [WBTimeLabel class])
1323 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1324 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1327 @interface UIView (WinterBoard)
1328 - (bool) wb$isWBImageView;
1329 - (void) wb$logHierarchy;
1330 - (void) wb$setBackgroundColor:(UIColor *)color;
1333 @implementation UIView (WinterBoard)
1335 - (bool) wb$isWBImageView {
1339 - (void) wb$logHierarchy {
1340 WBLogHierarchy(self);
1343 - (void) wb$setBackgroundColor:(UIColor *)color {
1344 [self setBackgroundColor:color];
1345 for (UIView *child in [self subviews])
1346 [child wb$setBackgroundColor:color];
1351 @interface WBImageView : UIImageView {
1354 - (bool) wb$isWBImageView;
1355 - (void) wb$updateFrame;
1358 @implementation WBImageView
1360 - (bool) wb$isWBImageView {
1364 - (void) wb$updateFrame {
1365 CGRect frame([self frame]);
1368 for (UIView *view(self); ; ) {
1369 view = [view superview];
1372 frame.origin.y -= [view frame].origin.y;
1375 [self setFrame:frame];
1380 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1381 NSArray *subviews([self subviews]);
1382 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1383 if (view != nil && [view wb$isWBImageView])
1384 [view wb$updateFrame];
1385 _SBIconList$setFrame$(self, sel, frame);
1388 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1389 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1390 NSArray *lists([_iconModel iconLists]);
1392 for (unsigned i(0), e([lists count]); i != e; ++i)
1393 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]])) {
1394 SBIconList *list([lists objectAtIndex:i]);
1395 NSArray *subviews([list subviews]);
1397 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1398 if (view == nil || ![view wb$isWBImageView]) {
1399 view = [[[WBImageView alloc] init] autorelease];
1400 [list insertSubview:view atIndex:0];
1403 UIImage *image([UIImage imageWithContentsOfFile:path]);
1405 CGRect frame([view frame]);
1406 frame.size = [image size];
1407 [view setFrame:frame];
1409 [view setImage:image];
1410 [view wb$updateFrame];
1413 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1416 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1417 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1419 [self setClipsToBounds:NO];
1423 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1424 static bool gssc(false);
1426 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1427 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1430 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1431 [Info_ setObject:[NSNumber numberWithBool:(
1433 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1434 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1435 )] forKey:@"UndockedIconLabels"];
1438 id &_label(MSHookIvar<id>(self, "_label"));
1439 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1442 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1443 [_label setInDock:docked];
1445 _SBIconLabel$setInDock$(self, sel, docked);
1446 [self setNeedsDisplay];
1449 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1450 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1453 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1454 _SBDockIconListView$setFrame$(self, sel, frame);
1457 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1458 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1459 NSString *identifier = [self bundleIdentifier];
1460 NSLocale *locale = [NSLocale currentLocale];
1461 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1463 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1464 NSString *file = table == nil ? @"Localizable" : table;
1465 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1466 NSDictionary *strings;
1467 if ((strings = [Strings_ objectForKey:name]) != nil) {
1468 if (static_cast<id>(strings) != [NSNull null]) strings:
1469 if (NSString *value = [strings objectForKey:key])
1471 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1474 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1475 [Strings_ setObject:[strings autorelease] forKey:name];
1479 [Strings_ setObject:[NSNull null] forKey:name];
1480 return MSOldCall(key, value, table);
1483 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1484 MSClassHook(WebCoreFrameBridge)
1486 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1489 void **core(reinterpret_cast<void **>([node _node]));
1490 if (core == NULL || core[6] == NULL)
1492 return MSOldCall(node, width);
1496 MSInstanceMessageHook1(void, SBIconLabel, drawRect, CGRect, rect) {
1497 CGRect bounds = [self bounds];
1499 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1502 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1503 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1505 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1507 NSString *style = [NSString stringWithFormat:@""
1508 "font-family: Helvetica; "
1509 "font-weight: bold; "
1511 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1512 ? @"font-size: 12px; "
1513 : @"font-size: 11px; "
1517 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1519 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1521 bool ellipsis(false);
1522 float max = [self frame].size.width - 11, width;
1524 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
1527 size_t length([label length]);
1528 float spacing((width - max) / (length - 1));
1530 if (spacing > 1.25) {
1532 label = [label substringToIndex:(length - 1)];
1536 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
1540 label = [label stringByAppendingString:@"..."];
1542 if (NSString *custom = [Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")])
1543 style = [style stringByAppendingString:custom];
1545 CGSize size = [label sizeWithStyle:style forWidth:bounds.size.width];
1546 [label drawAtPoint:CGPointMake((bounds.size.width - size.width) / 2, 0) withStyle:style];
1550 MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1551 if ((self = MSOldCall(frame, delegate)) != nil) {
1552 [self setBackgroundColor:[UIColor clearColor]];
1556 MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1557 return SMSBackgrounded_ ? NO : MSOldCall();
1560 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1561 [self wb$setBackgroundColor:[UIColor clearColor]];
1565 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1567 [balloon setBackgroundColor:[UIColor clearColor]];
1570 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1571 MSOldCall([UIColor clearColor]);
1572 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1576 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1577 if ((self = MSOldCall(style, reuse)) != nil) {
1578 [self setBackgroundColor:[UIColor clearColor]];
1579 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1584 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1585 if ((self = MSOldCall(style, reuse)) != nil) {
1586 [self setBackgroundColor:[UIColor clearColor]];
1587 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1591 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1592 if ((self = MSOldCall(style, reuse)) != nil) {
1593 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1594 [_label setBackgroundColor:[UIColor clearColor]];
1598 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1599 MSOldCall(UITableViewCellSeparatorStyleNone);
1602 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1603 if ((self = MSOldCall(frame, style)) != nil) {
1604 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1608 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1611 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1612 if (UIImage *image = $getImage$(path)) {
1613 SMSBackgrounded_ = true;
1615 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1616 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1618 if (&_transcriptTable != NULL)
1619 table = _transcriptTable;
1620 else if (&_transcriptLayer != NULL)
1621 table = _transcriptLayer;
1625 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1626 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1629 [placard insertSubview:background atIndex:0];
1631 [table setBackgroundColor:[UIColor clearColor]];
1632 [placard insertSubview:background belowSubview:table];
1638 // %hook _UIImageWithName() {{{
1639 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1641 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1648 if (_UIPackedImageTableGetIdentifierForName != NULL)
1649 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1650 else if (_UISharedImageNameGetIdentifier != NULL) {
1651 identifier = _UISharedImageNameGetIdentifier(name);
1652 packed = identifier != -1;
1659 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1662 return __UIImageWithName(name);
1664 NSNumber *key([NSNumber numberWithInt:identifier]);
1665 UIImage *image([UIImages_ objectForKey:key]);
1667 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1668 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1669 image = $getImage$(path);
1670 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1674 image = __UIImageWithName(name);
1677 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1678 if (![Manager_ fileExistsAtPath:path])
1679 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1686 // %hook _UIImageWithNameInDomain() {{{
1687 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1688 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1689 UIImage *image([PathImages_ objectForKey:key]);
1691 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1693 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1694 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1695 image = $getImage$(path);
1696 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1697 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1701 // %hook GSFontCreateWithName() {{{
1702 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1704 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1705 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1706 name = [font UTF8String];
1707 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1708 // size *= [scale floatValue];
1709 return _GSFontCreateWithName(name, traits, size);
1713 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1714 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1716 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1718 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1720 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1721 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1723 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1726 NSString *path = [NSString stringWithUTF8String:a1];
1727 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1728 NSString *file = [path substringFromIndex:31];
1729 for (NSString *theme in Themes_) {
1730 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1731 if ([Manager_ fileExistsAtPath:path]) {
1732 strcpy(a1, [path UTF8String]);
1741 static void ChangeWallpaper(
1742 CFNotificationCenterRef center,
1746 CFDictionaryRef info
1749 NSLog(@"WB:Debug:ChangeWallpaper!");
1752 if (WallpaperFile_ != nil) {
1753 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1755 image = [image autorelease];
1758 if (WallpaperImage_ != nil)
1759 [WallpaperImage_ setImage:image];
1760 if (WallpaperPage_ != nil)
1761 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1765 #define WBRename(name, sel, imp) \
1766 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
1768 template <typename Type_>
1769 static void msset(Type_ &function, MSImageRef image, const char *name) {
1770 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1773 template <typename Type_>
1774 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1775 struct nlist &name(nl[index]);
1776 uintptr_t value(name.n_value);
1777 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1778 value |= 0x00000001;
1779 function = reinterpret_cast<Type_>(value);
1782 template <typename Type_>
1783 static void dlset(Type_ &function, const char *name) {
1784 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1787 // %hook CGImageReadCreateWithFile() {{{
1788 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1790 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1791 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1792 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1798 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
1799 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1800 if (style == nil || [style length] == 0)
1801 style = @"font-family: Helvetica; font-size: 12px";
1802 return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
1805 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
1806 if (style == nil || [style length] == 0)
1807 style = @"font-family: Helvetica; font-size: 12px";
1808 return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width];
1811 static void SBInitialize() {
1812 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
1813 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
1816 WBRename(SBApplication, pathForIcon, pathForIcon);
1817 WBRename(SBApplicationIcon, icon, icon);
1818 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1821 WBRename(SBBookmarkIcon, icon, icon);
1822 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1823 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1824 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1825 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
1827 WBRename(SBWidgetApplicationIcon, icon, icon);
1829 WBRename(SBDockIconListView, setFrame:, setFrame$);
1830 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
1832 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
1833 WBRename(SBIconLabel, setInDock:, setInDock$);
1835 WBRename(SBIconList, setFrame:, setFrame$);
1837 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
1838 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
1839 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
1840 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
1842 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
1843 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
1844 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
1846 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
1848 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
1849 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
1850 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
1851 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
1852 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
1853 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
1854 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
1855 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
1856 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
1859 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
1863 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1865 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
1866 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
1868 Manager_ = [[NSFileManager defaultManager] retain];
1869 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
1871 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
1873 // Load Settings.plist {{{
1874 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
1875 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
1876 SummerBoard_ = [value boolValue];
1877 if (NSNumber *value = [settings objectForKey:@"Debug"])
1878 Debug_ = [value boolValue];
1879 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
1880 UIDebug_ = [value boolValue];
1882 NSArray *themes([settings objectForKey:@"Themes"]);
1884 if (NSString *theme = [settings objectForKey:@"Theme"])
1885 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
1887 [NSNumber numberWithBool:true], @"Active",
1891 for (NSDictionary *theme in themes) {
1892 NSNumber *active([theme objectForKey:@"Active"]);
1893 if (![active boolValue])
1896 NSString *name([theme objectForKey:@"Name"]);
1900 NSString *theme(nil);
1902 #define testForTheme(format...) \
1903 if (theme == nil) { \
1904 NSString *path = [NSString stringWithFormat:format]; \
1905 if ([Manager_ fileExistsAtPath:path]) { \
1906 [Themes_ addObject:path]; \
1911 testForTheme(@"/Library/Themes/%@.theme", name)
1912 testForTheme(@"/Library/Themes/%@", name)
1913 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
1918 // Merge Info.plist {{{
1919 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1921 for (NSString *theme in Themes_)
1922 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
1923 for (NSString *key in [info allKeys])
1924 if ([Info_ objectForKey:key] == nil)
1925 [Info_ setObject:[info objectForKey:key] forKey:key];
1929 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
1930 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
1931 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
1934 // GraphicsServices {{{
1936 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
1940 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
1941 void *(*CGImageReadCreateWithFile)(NSString *, int);
1942 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
1943 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
1948 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
1949 Papered_ = $getTheme$(Wallpapers_) != nil;
1950 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
1952 CFNotificationCenterAddObserver(
1953 CFNotificationCenterGetDarwinNotifyCenter(),
1954 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
1957 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
1958 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
1959 if (MediaPlayer != nil)
1962 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
1963 $MPVideoView = objc_getClass("MPVideoView");
1970 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
1972 memset(nl, 0, sizeof(nl));
1973 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
1974 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
1975 nl[2].n_un.n_name = (char *) "__UIKitBundle";
1976 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
1977 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
1980 nlset(_UIApplicationImageWithName, nl, 0);
1981 nlset(_UIImageWithNameInDomain, nl, 1);
1982 nlset(_UIKitBundle, nl, 2);
1983 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
1984 nlset(_UISharedImageNameGetIdentifier, nl, 4);
1986 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
1987 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
1988 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
1992 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
1993 NSError *error(nil);
1994 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
1995 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
1997 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);