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_ = false;
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 // XXX: this is not reasonable; OMG
300 @synchronized (Themed_) {
301 if (NSString *path = [Themed_ objectForKey:key])
302 return reinterpret_cast<id>(path) == [NSNull null] ? nil : path;
306 NSLog(@"WB:Debug: %@", [files description]);
310 for (NSString *theme in Themes_)
311 for (NSString *file in files) {
312 path = [NSString stringWithFormat:@"%@/%@", theme, file];
313 if ([Manager_ fileExistsAtPath:path])
320 @synchronized (Themed_) {
321 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:key];
327 // $pathForFile$inBundle$() {{{
328 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool ui) {
329 NSString *identifier = [bundle bundleIdentifier];
330 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
332 if (identifier != nil)
333 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
334 if (NSString *folder = [[bundle bundlePath] lastPathComponent]) {
335 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
336 NSString *base([folder stringByDeletingPathExtension]);
337 if ([base hasSuffix:@"~iphone"])
338 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 7)], [folder pathExtension], file]];
341 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
343 #define remapResourceName(oldname, newname) \
344 else if ([file isEqualToString:(oldname)]) \
345 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
347 bool summer(SpringBoard_ && SummerBoard_);
349 if (identifier == nil);
350 else if ([identifier isEqualToString:@"com.apple.chatkit"])
351 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
352 else if ([identifier isEqualToString:@"com.apple.calculator"])
353 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
355 remapResourceName(@"FSO_BG.png", @"StatusBar")
356 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
357 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
359 [names addObject:[NSString stringWithFormat:@"Fallback/%@", file]];
361 if (NSString *path = $getTheme$($useScale$(names, ui)))
368 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
369 NSString *identifier = [self bundleIdentifier];
370 NSString *path = [self path];
371 NSString *folder = [path lastPathComponent];
372 NSString *dname = [self displayName];
373 NSString *didentifier = [self displayIdentifier];
376 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
378 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
380 /* XXX: I might need to keep this for backwards compatibility
381 if (identifier != nil)
382 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
384 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
386 #define testForIcon(Name) \
387 if (NSString *name = Name) \
388 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
390 if (![didentifier isEqualToString:identifier])
391 testForIcon(didentifier);
393 testForIcon(identifier);
396 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
399 if (didentifier != nil) {
400 testForIcon([English_ objectForKey:didentifier]);
402 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
403 if ([parts count] != 1)
404 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
405 testForIcon([english objectForKey:[parts lastObject]]);
408 if (NSString *path = $getTheme$(names))
414 // -[NSBundle wb$bundleWithFile] {{{
415 @interface NSBundle (WinterBoard)
416 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
419 @implementation NSBundle (WinterBoard)
421 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
422 path = [path stringByDeletingLastPathComponent];
423 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
426 NSBundle *bundle([Bundles_ objectForKey:path]);
427 if (reinterpret_cast<id>(bundle) == [NSNull null])
429 else if (bundle == nil) {
430 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
431 bundle = [NSBundle bundleWithPath:path];
433 bundle = [NSBundle wb$bundleWithFile:path];
435 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
436 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
444 // -[NSString wb$themedPath] {{{
445 @interface NSString (WinterBoard)
446 - (NSString *) wb$themedPath;
449 @implementation NSString (WinterBoard)
451 - (NSString *) wb$themedPath {
452 if ([self hasPrefix:@"/Library/Themes/"])
456 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
458 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
459 NSString *file([self stringByResolvingSymlinksInPath]);
460 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
461 if ([file hasPrefix:prefix]) {
462 NSUInteger length([prefix length]);
463 if (length != [file length])
464 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
475 void WBLogRect(const char *tag, struct CGRect rect) {
476 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
479 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
480 CGRect frame([view frame]);
481 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]);
483 for (UIView *child in [view subviews])
484 WBLogHierarchy(child, index++, indent + 1);
487 UIImage *$cacheForImage$(UIImage *image) {
488 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
489 CGRect rect = {CGPointMake(1, 1), [image size]};
490 CGSize size = {rect.size.width + 2, rect.size.height + 2};
492 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
493 CGColorSpaceRelease(space);
495 CGContextDrawImage(context, rect, [image CGImage]);
496 CGImageRef ref(CGBitmapContextCreateImage(context));
497 CGContextRelease(context);
499 UIImage *cache([UIImage imageWithCGImage:ref]);
505 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
506 //if ([name isEqualToString:@"icons"]) return nil;
507 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
510 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
511 NSString *key([icon displayIdentifier]);
513 if (UIImage *image = [icon icon]) {
514 CGSize size = [image size];
515 if (size.width != 59 || size.height != 60) {
516 UIImage *cache($cacheForImage$(image));
517 [Cache_ setObject:cache forKey:key];
522 _SBIconModel$cacheImageForIcon$(self, sel, icon);
525 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
526 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
527 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
529 NSString *key([icon displayIdentifier]);
531 if (UIImage *image = [icon icon]) {
532 CGSize size = [image size];
533 if (size.width != 59 || size.height != 60) {
534 UIImage *cache($cacheForImage$(image));
535 [Cache_ setObject:cache forKey:key];
541 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
542 NSString *key([icon displayIdentifier]);
543 if (UIImage *image = [Cache_ objectForKey:key])
546 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
549 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
551 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
552 NSString *key([icon displayIdentifier]);
553 if (UIImage *image = [Cache_ objectForKey:key])
556 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
559 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
560 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
561 [self setBackgroundColor:[UIColor clearColor]];
562 for (UIView *child in [self subviews])
563 [child setBackgroundColor:[UIColor clearColor]];
567 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
568 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
569 [self setBackgroundColor:[UIColor clearColor]];
573 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
574 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
575 float inset([self edgeInset]);
576 [[UIColor clearColor] set];
577 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
578 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
581 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
582 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
583 if (NSString *path = $pathForIcon$([self application]))
584 return [UIImage imageWithContentsOfFile:path];
585 return _SBApplicationIcon$icon(self, sel);
588 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
590 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
591 if (IsWild_ && false) // XXX: delete this code, it should not be supported
592 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
593 return [UIImage imageWithContentsOfFile:path72];
594 if (NSString *path = $pathForIcon$([self application]))
595 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
597 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
598 width = [$SBIcon defaultIconImageSize].width;
601 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
604 return _SBApplicationIcon$generateIconImage$(self, sel, type);
607 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
609 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
610 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
611 return [UIImage imageWithContentsOfFile:path];
612 return _SBWidgetApplicationIcon$icon(self, sel);
615 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
617 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
618 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
619 return [UIImage imageWithContentsOfFile:path];
620 return _SBBookmarkIcon$icon(self, sel);
623 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
624 if (NSString *path = $pathForIcon$(self))
626 return _SBApplication$pathForIcon(self, sel);
629 static UIImage *CachedImageAtPath(NSString *path) {
630 path = [path stringByResolvingSymlinksInPath];
631 UIImage *image = [PathImages_ objectForKey:path];
633 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
634 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
636 image = [image autorelease];
637 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
641 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
642 NSBundle *bundle = [NSBundle mainBundle];
644 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
645 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
646 return CachedImageAtPath(path);
647 return __UIApplicationImageWithName(name);
650 #define WBDelegate(delegate) \
651 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
653 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
654 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
656 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
660 - (void) forwardInvocation:(NSInvocation*)inv { \
661 SEL sel = [inv selector]; \
662 if ([delegate respondsToSelector:sel]) \
663 [inv invokeWithTarget:delegate]; \
665 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
668 // %hook -[NSBundle pathForResource:ofType:] {{{
669 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
670 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
672 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
673 if (NSString *path = $pathForFile$inBundle$(file, self, false))
675 return MSOldCall(resource, type);
679 static void $drawLabel$(NSString *label, CGRect rect, NSString *style, NSString *custom) {
680 bool ellipsis(false);
681 float max = rect.size.width - 11, width;
683 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
686 size_t length([label length]);
687 float spacing((width - max) / (length - 1));
689 if (spacing > 1.25) {
691 label = [label substringToIndex:(length - 1)];
695 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
699 label = [label stringByAppendingString:@"..."];
702 style = [style stringByAppendingString:custom];
704 CGSize size = [label sizeWithStyle:style forWidth:rect.size.width];
705 [label drawAtPoint:CGPointMake((rect.size.width - size.width) / 2 + rect.origin.x, rect.origin.y) withStyle:style];
708 static struct WBStringDrawingState {
709 WBStringDrawingState *next_;
713 } *stringDrawingState_;
715 MSInstanceMessageHook6(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode,letterSpacing,includeEmoji, CGPoint, point, float, width, UIFont *, font, UILineBreakMode, mode, float, spacing, BOOL, emoji) {
716 //NSLog(@"XXX: @\"%@\" %g", self, spacing);
718 WBStringDrawingState *state(stringDrawingState_);
720 return MSOldCall(point, width, font, mode, spacing, emoji);
722 if (--state->count_ == 0)
723 stringDrawingState_ = state->next_;
724 if (state->info_ == nil)
725 return MSOldCall(point, width, font, mode, spacing, emoji);
727 NSString *info([Info_ objectForKey:state->info_]);
729 return MSOldCall(point, width, font, mode, spacing, emoji);
731 NSString *base(state->base_ ?: @"");
732 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
733 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], extra, base, info]];
737 extern "C" NSString *NSStringFromCGRect(CGRect rect);
739 MSInstanceMessageHook7(CGSize, NSString, _drawInRect,withFont,lineBreakMode,alignment,lineSpacing,includeEmoji,truncationRect, CGRect, rect, UIFont *, font, UILineBreakMode, mode, UITextAlignment, alignment, float, spacing, BOOL, emoji, CGRect, truncation) {
740 //NSLog(@"XXX: &\"%@\" %@ \"%@\" %u %u %g %u %@", self, NSStringFromCGRect(rect), font, mode, alignment, spacing, emoji, NSStringFromCGRect(truncation));
742 WBStringDrawingState *state(stringDrawingState_);
744 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
746 if (--state->count_ == 0)
747 stringDrawingState_ = state->next_;
748 if (state->info_ == nil)
749 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
751 NSString *info([Info_ objectForKey:state->info_]);
753 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
758 case UITextAlignmentLeft:
761 case UITextAlignmentCenter:
762 textAlign = @"center";
764 case UITextAlignmentRight:
765 textAlign = @"right";
769 NSString *base(state->base_ ?: @"");
770 NSString *extra([NSString stringWithFormat:@"text-align: %@", textAlign]);
773 $drawLabel$(self, rect, [NSString stringWithFormat:@"%@;%@", [font markupDescription], base], info);
775 [self drawInRect:rect withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], extra, base, info]];
780 MSInstanceMessageHook4(CGSize, NSString, sizeWithFont,forWidth,lineBreakMode,letterSpacing, UIFont *, font, float, width, UILineBreakMode, mode, float, spacing) {
781 //NSLog(@"XXX: #\"%@\" \"%@\" %g %u %g", self, font, width, mode, spacing);
783 WBStringDrawingState *state(stringDrawingState_);
785 return MSOldCall(font, width, mode, spacing);
787 if (--state->count_ == 0)
788 stringDrawingState_ = state->next_;
789 if (state->info_ == nil)
790 return MSOldCall(font, width, mode, spacing);
792 NSString *info([Info_ objectForKey:state->info_]);
794 return MSOldCall(font, width, mode, spacing);
796 NSString *base(state->base_ ?: @"");
797 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
798 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], extra, base, info] forWidth:width];
801 MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) {
802 //NSLog(@"XXX: ?\"%@\"", self);
804 WBStringDrawingState *state(stringDrawingState_);
806 return MSOldCall(font);
808 if (--state->count_ == 0)
809 stringDrawingState_ = state->next_;
810 if (state->info_ == nil)
811 return MSOldCall(font);
813 NSString *info([Info_ objectForKey:state->info_]);
815 return MSOldCall(font);
817 NSString *base(state->base_ ?: @"");
818 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info] forWidth:65535];
821 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
822 WBStringDrawingState badgeState = {NULL, 1, @""
826 stringDrawingState_ = &badgeState;
828 UIImage *image(MSOldCall(text));
830 stringDrawingState_ = NULL;
834 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
835 WBStringDrawingState dayState = {NULL, 2, @""
837 // XXX: this is only correct on an iPod dock
838 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
839 , @"CalendarIconDayStyle"};
841 WBStringDrawingState sizeState = {&dayState, 7, nil, nil};
843 WBStringDrawingState dateState = {&sizeState, 2, @""
845 , @"CalendarIconDateStyle"};
847 stringDrawingState_ = &dateState;
849 UIImage *image(MSOldCall(type));
851 stringDrawingState_ = NULL;
855 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
856 NSBundle *bundle([NSBundle mainBundle]);
858 CFLocaleRef locale(CFLocaleCopyCurrent());
859 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
862 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
864 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
865 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
866 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
867 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
871 CFRelease(formatter);
873 NSString *datestyle([@""
874 "font-family: Helvetica; "
875 "font-weight: bold; "
878 "" stringByAppendingString:(IsWild_
879 ? @"font-size: 54px; "
880 : @"font-size: 39px; "
883 NSString *daystyle([@""
884 "font-family: Helvetica; "
885 "font-weight: bold; "
887 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
888 "" stringByAppendingString:(IsWild_
889 ? @"font-size: 11px; "
890 : @"font-size: 9px; "
893 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
894 datestyle = [datestyle stringByAppendingString:style];
895 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
896 daystyle = [daystyle stringByAppendingString:style];
898 float width([self bounds].size.width);
900 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
901 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
903 unsigned base0(IsWild_ ? 89 : 70);
904 if ($GSFontGetUseLegacyFontMetrics())
906 unsigned base1(IsWild_ ? 18 : 16);
913 [(NSString *)date drawAtPoint:CGPointMake(
914 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
915 ) withStyle:datestyle];
917 [(NSString *)day drawAtPoint:CGPointMake(
918 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
919 ) withStyle:daystyle];
925 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
926 void $setBarStyle$_(NSString *name, int &style) {
928 NSLog(@"WB:Debug:%@Style:%d", name, style);
929 NSNumber *number = nil;
931 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
933 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
935 style = [number intValue];
937 NSLog(@"WB:Debug:%@Style=%d", name, style);
941 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
942 $setBarStyle$_(@"Toolbar", style);
943 return MSOldCall(style);
946 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
947 $setBarStyle$_(@"NavigationBar", style);
948 return MSOldCall(style);
952 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
953 [[self superview] setBackgroundColor:[UIColor clearColor]];
954 _SBButtonBar$didMoveToSuperview(self, sel);
957 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
958 [[self superview] setBackgroundColor:[UIColor clearColor]];
959 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
962 static NSArray *Wallpapers_;
963 static bool Papered_;
965 static bool SMSBackgrounded_;
966 static NSString *WallpaperFile_;
967 static UIImageView *WallpaperImage_;
968 static UIWebDocumentView *WallpaperPage_;
969 static NSURL *WallpaperURL_;
971 #define _release(object) \
972 do if (object != nil) { \
977 static UIImage *$getImage$(NSString *path) {
978 UIImage *image([UIImage imageWithContentsOfFile:path]);
980 unsigned scale($getScale$(path));
981 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
982 [image setScale:scale];
987 static UIImage *$getDefaultDesktopImage$() {
988 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
989 return $getImage$(path);
993 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
994 return $getDefaultDesktopImage$() ?: MSOldCall();
997 MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
998 return $getDefaultDesktopImage$() ?: MSOldCall();
1001 MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
1002 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
1003 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
1004 if (UIImage *image = $getDefaultDesktopImage$()) {
1005 [self setImage:image];
1015 // %hook -[SBUIController init] {{{
1016 MSInstanceMessageHook0(id, SBUIController, init) {
1021 NSString *paper($getTheme$(Wallpapers_));
1023 paper = [paper stringByDeletingLastPathComponent];
1027 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
1028 char *machine = new char[size];
1030 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
1031 perror("sysctlbyname(\"hw.machine\", ?)");
1036 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
1040 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
1043 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
1044 if (&_wallpaperView != NULL) {
1045 [_wallpaperView removeFromSuperview];
1046 [_wallpaperView release];
1047 _wallpaperView = nil;
1051 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
1052 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
1055 if (&_contentLayer != NULL)
1056 player = &_contentLayer;
1057 else if (&_contentView != NULL)
1058 player = &_contentView;
1061 UIView *layer(player == NULL ? nil : *player);
1063 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
1064 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
1065 [window setContentView:content];
1067 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
1068 [window setBackgroundColor:[_window backgroundColor]];
1069 [_window setBackgroundColor:[UIColor clearColor]];
1071 [window setLevel:-1000];
1072 [window setHidden:NO];
1074 /*if (player != NULL)
1075 *player = content;*/
1077 [content setBackgroundColor:[layer backgroundColor]];
1078 [layer setBackgroundColor:[UIColor clearColor]];
1081 if (!SummerBoard_ || !IsWild_)
1084 CGRect bounds([content bounds]);
1085 bounds.origin.y = -30;
1086 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
1087 [content addSubview:indirect];
1088 [indirect zoomToScale:2.4];
1091 _release(WallpaperFile_);
1092 _release(WallpaperImage_);
1093 _release(WallpaperPage_);
1094 _release(WallpaperURL_);
1097 NSArray *themes([NSArray arrayWithObject:paper]);
1099 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1103 static AVController *controller_(nil);
1104 if (controller_ == nil) {
1105 AVQueue *queue([AVQueue avQueue]);
1106 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1109 AVQueue *queue([controller_ queue]);
1111 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1112 [controller_ setLayer:[video _layer]];
1114 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1115 [queue appendItem:item error:&error];
1117 [controller_ play:&error];
1118 #elif UseMPMoviePlayerController
1119 NSURL *url([NSURL fileURLWithPath:path]);
1120 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1121 controller.movieControlMode = MPMovieControlModeHidden;
1124 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1125 [video setMovieWithPath:path];
1126 [video setRepeatMode:1];
1127 [video setRepeatGap:-1];
1128 [video playFromBeginning];;
1131 [indirect addSubview:video];
1134 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1135 if (UIImage *image = $getImage$(path)) {
1136 WallpaperFile_ = [path retain];
1137 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1138 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1139 [WallpaperImage_ setAlpha:[number floatValue]];
1140 [indirect addSubview:WallpaperImage_];
1144 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1145 CGRect bounds = [indirect bounds];
1147 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1148 [view setAutoresizes:true];
1150 WallpaperPage_ = [view retain];
1151 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1153 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1155 [view setBackgroundColor:[UIColor clearColor]];
1156 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1157 [view setDrawsBackground:NO];
1158 [[view webView] setDrawsBackground:NO];
1160 [indirect addSubview:view];
1164 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1165 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1166 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1167 if ([Manager_ fileExistsAtPath:html]) {
1168 CGRect bounds = [indirect bounds];
1170 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1171 [view setAutoresizes:true];
1173 NSURL *url = [NSURL fileURLWithPath:html];
1174 [view loadRequest:[NSURLRequest requestWithURL:url]];
1176 [view setBackgroundColor:[UIColor clearColor]];
1177 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1178 [view setDrawsBackground:NO];
1179 [[view webView] setDrawsBackground:NO];
1181 [indirect addSubview:view];
1189 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1190 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1191 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1193 if (path != nil && _backgroundView != nil)
1196 _SBAwayView$updateDesktopImage$(self, sel, image);
1199 CGRect bounds = [self bounds];
1201 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1202 [view setAutoresizes:true];
1204 if (WallpaperPage_ != nil)
1205 [WallpaperPage_ release];
1206 WallpaperPage_ = [view retain];
1208 if (WallpaperURL_ != nil)
1209 [WallpaperURL_ release];
1210 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1212 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1214 [[view webView] setDrawsBackground:false];
1215 [view setBackgroundColor:[UIColor clearColor]];
1217 [self insertSubview:view aboveSubview:_backgroundView];
1221 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1222 extern "C" CGColorRef CGGStateGetFillColor(void *);
1223 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1224 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1226 /* WBTimeLabel {{{ */
1227 @interface WBTimeLabel : NSProxy {
1229 _transient SBStatusBarTimeView *view_;
1232 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1236 @implementation WBTimeLabel
1243 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1244 time_ = [time retain];
1249 - (NSString *) description {
1255 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1256 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1257 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1259 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1260 "font-family: Helvetica; "
1261 "font-weight: bold; "
1264 "%@", _mode ? @"white" : @"black", custom]];
1269 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1274 /* WBBadgeLabel {{{ */
1275 @interface WBBadgeLabel : NSProxy {
1279 - (id) initWithBadge:(NSString *)badge;
1280 - (NSString *) description;
1284 @implementation WBBadgeLabel
1291 - (id) initWithBadge:(NSString *)badge {
1292 badge_ = [badge retain];
1296 - (NSString *) description {
1297 return [badge_ description];
1302 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1303 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1304 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1305 "font-family: Helvetica; "
1306 "font-weight: bold; "
1314 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1321 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1322 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1323 alpha = [number floatValue];
1324 return MSOldCall(alpha);
1327 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1328 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1329 alpha = [number floatValue];
1330 return MSOldCall(alpha);
1333 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1334 if ((self = MSOldCall()) != nil) {
1335 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1336 // XXX: note: this is overridden above, which is silly
1337 float alpha([number floatValue]);
1338 [self setIconImageAlpha:alpha];
1339 [self setIconLabelAlpha:alpha];
1344 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1345 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1346 alpha = [number floatValue];
1347 return MSOldCall(alpha);
1351 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1352 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1353 id &_badge(MSHookIvar<id>(self, "_badge"));
1355 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1360 void SBStatusBarController$setStatusBarMode(int &mode) {
1362 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1363 if (mode < 100) // 104:hidden 105:glowing
1364 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1365 mode = [number intValue];
1368 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1369 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1370 SBStatusBarController$setStatusBarMode(mode);
1371 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1374 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1375 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1376 SBStatusBarController$setStatusBarMode(mode);
1377 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1380 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) {
1381 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1382 SBStatusBarController$setStatusBarMode(mode);
1383 //NSLog(@"mode=%u", mode);
1384 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1387 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1388 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1389 mode = [number intValue];
1390 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1393 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1394 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1396 NSLog(@"operatorNameStyle= %@", style);
1397 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1398 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1402 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1404 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1405 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1408 // XXX: replace this with [SBStatusBarTimeView tile]
1409 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1410 id &_time(MSHookIvar<id>(self, "_time"));
1411 if (_time != nil && [_time class] != [WBTimeLabel class])
1412 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1413 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1416 @interface UIView (WinterBoard)
1417 - (bool) wb$isWBImageView;
1418 - (void) wb$logHierarchy;
1419 - (void) wb$setBackgroundColor:(UIColor *)color;
1422 @implementation UIView (WinterBoard)
1424 - (bool) wb$isWBImageView {
1428 - (void) wb$logHierarchy {
1429 WBLogHierarchy(self);
1432 - (void) wb$setBackgroundColor:(UIColor *)color {
1433 [self setBackgroundColor:color];
1434 for (UIView *child in [self subviews])
1435 [child wb$setBackgroundColor:color];
1440 @interface WBImageView : UIImageView {
1443 - (bool) wb$isWBImageView;
1444 - (void) wb$updateFrame;
1447 @implementation WBImageView
1449 - (bool) wb$isWBImageView {
1453 - (void) wb$updateFrame {
1454 CGRect frame([self frame]);
1457 for (UIView *view(self); ; ) {
1458 view = [view superview];
1461 frame.origin.y -= [view frame].origin.y;
1464 [self setFrame:frame];
1469 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1470 NSArray *subviews([self subviews]);
1471 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1472 if (view != nil && [view wb$isWBImageView])
1473 [view wb$updateFrame];
1474 _SBIconList$setFrame$(self, sel, frame);
1477 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1478 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1479 NSArray *lists([_iconModel iconLists]);
1481 for (unsigned i(0), e([lists count]); i != e; ++i)
1482 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]])) {
1483 SBIconList *list([lists objectAtIndex:i]);
1484 NSArray *subviews([list subviews]);
1486 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1487 if (view == nil || ![view wb$isWBImageView]) {
1488 view = [[[WBImageView alloc] init] autorelease];
1489 [list insertSubview:view atIndex:0];
1492 UIImage *image([UIImage imageWithContentsOfFile:path]);
1494 CGRect frame([view frame]);
1495 frame.size = [image size];
1496 [view setFrame:frame];
1498 [view setImage:image];
1499 [view wb$updateFrame];
1502 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1505 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1506 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1508 [self setClipsToBounds:NO];
1512 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1513 static bool gssc(false);
1515 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1516 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1519 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1520 [Info_ setObject:[NSNumber numberWithBool:(
1522 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1523 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1524 )] forKey:@"UndockedIconLabels"];
1527 id &_label(MSHookIvar<id>(self, "_label"));
1528 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1531 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1532 [_label setInDock:docked];
1534 _SBIconLabel$setInDock$(self, sel, docked);
1535 [self setNeedsDisplay];
1538 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1539 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1542 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1543 _SBDockIconListView$setFrame$(self, sel, frame);
1546 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1547 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1548 NSString *identifier = [self bundleIdentifier];
1549 NSLocale *locale = [NSLocale currentLocale];
1550 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1552 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1553 NSString *file = table == nil ? @"Localizable" : table;
1554 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1555 NSDictionary *strings;
1556 if ((strings = [Strings_ objectForKey:name]) != nil) {
1557 if (static_cast<id>(strings) != [NSNull null]) strings:
1558 if (NSString *value = [strings objectForKey:key])
1560 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1563 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1564 [Strings_ setObject:[strings autorelease] forKey:name];
1568 [Strings_ setObject:[NSNull null] forKey:name];
1569 return MSOldCall(key, value, table);
1572 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1573 MSClassHook(WebCoreFrameBridge)
1575 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1578 void **core(reinterpret_cast<void **>([node _node]));
1579 if (core == NULL || core[6] == NULL)
1581 return MSOldCall(node, width);
1585 MSInstanceMessage1(void, SBIconLabel, drawRect, CGRect, rect) {
1586 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1589 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1590 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1592 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1594 NSString *style = [NSString stringWithFormat:@""
1595 "font-family: Helvetica; "
1596 "font-weight: bold; "
1598 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1599 ? @"font-size: 12px; "
1600 : @"font-size: 11px; "
1604 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1606 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1608 NSString *custom([Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")]);
1610 $drawLabel$(label, [self bounds], style, custom);
1613 MSInstanceMessage0(CGImageRef, SBIconLabel, buildLabelImage) {
1614 bool docked((MSHookIvar<unsigned>(self, "_inDock") & 0x2) != 0);
1616 WBStringDrawingState labelState = {NULL, 0, @""
1618 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1620 stringDrawingState_ = &labelState;
1623 CGImageRef image(MSOldCall());
1626 stringDrawingState_ = NULL;
1631 MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1632 if ((self = MSOldCall(frame, delegate)) != nil) {
1633 [self setBackgroundColor:[UIColor clearColor]];
1637 MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1638 return SMSBackgrounded_ ? NO : MSOldCall();
1641 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1642 [self wb$setBackgroundColor:[UIColor clearColor]];
1646 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1648 [balloon setBackgroundColor:[UIColor clearColor]];
1651 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1652 MSOldCall([UIColor clearColor]);
1653 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1657 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1658 if ((self = MSOldCall(style, reuse)) != nil) {
1659 [self setBackgroundColor:[UIColor clearColor]];
1660 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1665 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1666 if ((self = MSOldCall(style, reuse)) != nil) {
1667 [self setBackgroundColor:[UIColor clearColor]];
1668 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1672 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1673 if ((self = MSOldCall(style, reuse)) != nil) {
1674 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1675 [_label setBackgroundColor:[UIColor clearColor]];
1679 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1680 MSOldCall(UITableViewCellSeparatorStyleNone);
1683 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1684 if ((self = MSOldCall(frame, style)) != nil) {
1685 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1689 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1692 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1693 if (UIImage *image = $getImage$(path)) {
1694 SMSBackgrounded_ = true;
1696 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1697 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1699 if (&_transcriptTable != NULL)
1700 table = _transcriptTable;
1701 else if (&_transcriptLayer != NULL)
1702 table = _transcriptLayer;
1706 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1707 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1710 [placard insertSubview:background atIndex:0];
1712 [table setBackgroundColor:[UIColor clearColor]];
1713 [placard insertSubview:background belowSubview:table];
1719 // %hook _UIImageWithName() {{{
1720 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1722 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1729 if (_UIPackedImageTableGetIdentifierForName != NULL)
1730 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1731 else if (_UISharedImageNameGetIdentifier != NULL) {
1732 identifier = _UISharedImageNameGetIdentifier(name);
1733 packed = identifier != -1;
1740 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1743 return __UIImageWithName(name);
1745 NSNumber *key([NSNumber numberWithInt:identifier]);
1746 UIImage *image([UIImages_ objectForKey:key]);
1748 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1749 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1750 image = $getImage$(path);
1751 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1755 image = __UIImageWithName(name);
1758 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1759 if (![Manager_ fileExistsAtPath:path])
1760 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1767 // %hook _UIImageWithNameInDomain() {{{
1768 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1769 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1770 UIImage *image([PathImages_ objectForKey:key]);
1772 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1774 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1775 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1776 image = $getImage$(path);
1777 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1778 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1782 // %hook GSFontCreateWithName() {{{
1783 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1785 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1786 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1787 name = [font UTF8String];
1788 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1789 // size *= [scale floatValue];
1790 return _GSFontCreateWithName(name, traits, size);
1794 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1795 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1797 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1799 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1801 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1802 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1804 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1807 NSString *path = [NSString stringWithUTF8String:a1];
1808 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1809 NSString *file = [path substringFromIndex:31];
1810 for (NSString *theme in Themes_) {
1811 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1812 if ([Manager_ fileExistsAtPath:path]) {
1813 strcpy(a1, [path UTF8String]);
1822 static void ChangeWallpaper(
1823 CFNotificationCenterRef center,
1827 CFDictionaryRef info
1830 NSLog(@"WB:Debug:ChangeWallpaper!");
1833 if (WallpaperFile_ != nil) {
1834 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1836 image = [image autorelease];
1839 if (WallpaperImage_ != nil)
1840 [WallpaperImage_ setImage:image];
1841 if (WallpaperPage_ != nil)
1842 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1846 #define WBRename(name, sel, imp) \
1847 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
1849 template <typename Type_>
1850 static void msset(Type_ &function, MSImageRef image, const char *name) {
1851 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1854 template <typename Type_>
1855 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1856 struct nlist &name(nl[index]);
1857 uintptr_t value(name.n_value);
1858 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1859 value |= 0x00000001;
1860 function = reinterpret_cast<Type_>(value);
1863 template <typename Type_>
1864 static void dlset(Type_ &function, const char *name) {
1865 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1868 // %hook CGImageReadCreateWithFile() {{{
1869 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1871 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1872 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1873 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1879 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
1880 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1881 if (style == nil || [style length] == 0)
1882 style = @"font-family: Helvetica; font-size: 12px";
1883 //NSLog(@"XXX:draw(%@)", [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
1884 return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
1887 static void NSString$drawInRect$withStyle$(NSString *self, SEL _cmd, CGRect rect, NSString *style) {
1888 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1889 if (style == nil || [style length] == 0)
1890 style = @"font-family: Helvetica; font-size: 12px";
1891 return [[WBMarkup sharedMarkup] drawString:self inRect:rect withStyle:style];
1894 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
1895 if (style == nil || [style length] == 0)
1896 style = @"font-family: Helvetica; font-size: 12px";
1897 //NSLog(@"XXX:size(%@)", [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
1898 return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width];
1901 static void SBInitialize() {
1902 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
1903 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v28@0:4{CGRect={CGSize=ff}{CGSize=ff}}8@24");
1904 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
1907 WBRename(SBApplication, pathForIcon, pathForIcon);
1908 WBRename(SBApplicationIcon, icon, icon);
1909 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1912 WBRename(SBBookmarkIcon, icon, icon);
1913 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1914 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1915 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1916 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
1918 WBRename(SBWidgetApplicationIcon, icon, icon);
1920 WBRename(SBDockIconListView, setFrame:, setFrame$);
1921 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
1923 if (kCFCoreFoundationVersionNumber < 600 || SummerBoard_)
1924 WBRename(SBIconLabel, drawRect:, drawRect$);
1926 WBRename(SBIconLabel, buildLabelImage, buildLabelImage);
1928 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
1929 WBRename(SBIconLabel, setInDock:, setInDock$);
1931 WBRename(SBIconList, setFrame:, setFrame$);
1933 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
1934 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
1935 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
1936 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
1938 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
1939 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
1940 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
1942 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
1944 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
1945 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
1946 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
1947 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
1948 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
1949 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
1950 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
1951 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
1952 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
1955 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
1959 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1961 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
1962 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
1964 Manager_ = [[NSFileManager defaultManager] retain];
1965 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
1967 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
1969 // Load Settings.plist {{{
1970 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
1971 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
1972 SummerBoard_ = [value boolValue];
1974 SummerBoard_ = true;
1976 if (NSNumber *value = [settings objectForKey:@"Debug"])
1977 Debug_ = [value boolValue];
1978 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
1979 UIDebug_ = [value boolValue];
1981 NSArray *themes([settings objectForKey:@"Themes"]);
1983 if (NSString *theme = [settings objectForKey:@"Theme"])
1984 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
1986 [NSNumber numberWithBool:true], @"Active",
1990 for (NSDictionary *theme in themes) {
1991 NSNumber *active([theme objectForKey:@"Active"]);
1992 if (![active boolValue])
1995 NSString *name([theme objectForKey:@"Name"]);
1999 NSString *theme(nil);
2001 #define testForTheme(format...) \
2002 if (theme == nil) { \
2003 NSString *path = [NSString stringWithFormat:format]; \
2004 if ([Manager_ fileExistsAtPath:path]) { \
2005 [Themes_ addObject:path]; \
2010 testForTheme(@"/Library/Themes/%@.theme", name)
2011 testForTheme(@"/Library/Themes/%@", name)
2012 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
2017 // Merge Info.plist {{{
2018 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2020 for (NSString *theme in Themes_)
2021 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
2022 for (NSString *key in [info allKeys])
2023 if ([Info_ objectForKey:key] == nil)
2024 [Info_ setObject:[info objectForKey:key] forKey:key];
2028 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
2029 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
2030 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
2033 // GraphicsServices {{{
2035 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
2039 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
2040 void *(*CGImageReadCreateWithFile)(NSString *, int);
2041 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
2042 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
2047 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
2048 Papered_ = $getTheme$(Wallpapers_) != nil;
2049 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
2051 CFNotificationCenterAddObserver(
2052 CFNotificationCenterGetDarwinNotifyCenter(),
2053 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
2056 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
2057 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
2058 if (MediaPlayer != nil)
2061 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
2062 $MPVideoView = objc_getClass("MPVideoView");
2069 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
2071 memset(nl, 0, sizeof(nl));
2072 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
2073 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
2074 nl[2].n_un.n_name = (char *) "__UIKitBundle";
2075 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
2076 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
2079 nlset(_UIApplicationImageWithName, nl, 0);
2080 nlset(_UIImageWithNameInDomain, nl, 1);
2081 nlset(_UIKitBundle, nl, 2);
2082 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
2083 nlset(_UISharedImageNameGetIdentifier, nl, 4);
2085 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
2086 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
2087 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
2091 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
2092 NSError *error(nil);
2093 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
2094 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
2096 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);