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(SBIconContentView)
145 MSClassHook(SBIconController)
146 MSClassHook(SBIconLabel)
147 MSClassHook(SBIconList)
148 MSClassHook(SBIconModel)
149 //MSClassHook(SBImageCache)
150 MSClassHook(SBSearchView)
151 MSClassHook(SBSearchTableViewCell)
152 MSClassHook(SBSlidingAlertDisplay)
153 MSClassHook(SBStatusBarContentsView)
154 MSClassHook(SBStatusBarController)
155 MSClassHook(SBStatusBarOperatorNameView)
156 MSClassHook(SBStatusBarTimeView)
157 MSClassHook(SBUIController)
158 MSClassHook(SBWallpaperView)
159 MSClassHook(SBWidgetApplicationIcon)
161 extern "C" void WKSetCurrentGraphicsContext(CGContextRef);
163 static struct MSFixClass { MSFixClass() {
164 $SBIcon = objc_getClass("SBIconView") ?: $SBIcon;
166 if ($SBIconList == nil)
167 $SBIconList = objc_getClass("SBIconListView");
168 if ($CKTranscriptController == nil)
169 $CKTranscriptController = objc_getClass("mSMSMessageTranscriptController");
173 static bool Four_($SBDockIconListView != nil);
175 @interface NSDictionary (WinterBoard)
176 - (UIColor *) wb$colorForKey:(NSString *)key;
177 - (BOOL) wb$boolForKey:(NSString *)key;
180 @implementation NSDictionary (WinterBoard)
182 - (UIColor *) wb$colorForKey:(NSString *)key {
183 NSString *value = [self objectForKey:key];
190 - (BOOL) wb$boolForKey:(NSString *)key {
191 if (NSString *value = [self objectForKey:key])
192 return [value boolValue];
198 static BOOL (*_GSFontGetUseLegacyFontMetrics)();
199 #define $GSFontGetUseLegacyFontMetrics() \
200 (_GSFontGetUseLegacyFontMetrics == NULL ? YES : _GSFontGetUseLegacyFontMetrics())
202 static bool Debug_ = false;
203 static bool UIDebug_ = false;
204 static bool Engineer_ = false;
205 static bool SummerBoard_ = false;
206 static bool SpringBoard_;
208 static UIImage *(*_UIApplicationImageWithName)(NSString *name);
209 static UIImage *(*_UIImageWithNameInDomain)(NSString *name, NSString *domain);
210 static NSBundle *(*_UIKitBundle)();
211 static bool (*_UIPackedImageTableGetIdentifierForName)(NSString *, int *);
212 static int (*_UISharedImageNameGetIdentifier)(NSString *);
214 static NSMutableDictionary *UIImages_ = [[NSMutableDictionary alloc] initWithCapacity:32];
215 static NSMutableDictionary *PathImages_ = [[NSMutableDictionary alloc] initWithCapacity:16];
216 static NSMutableDictionary *Cache_ = [[NSMutableDictionary alloc] initWithCapacity:64];
217 static NSMutableDictionary *Strings_ = [[NSMutableDictionary alloc] initWithCapacity:0];
218 static NSMutableDictionary *Bundles_ = [[NSMutableDictionary alloc] initWithCapacity:2];
220 static NSFileManager *Manager_;
221 static NSMutableArray *Themes_;
223 static NSDictionary *English_;
224 static NSMutableDictionary *Info_;
227 static NSMutableDictionary *Themed_ = [[NSMutableDictionary alloc] initWithCapacity:128];
229 static unsigned Scale_ = 0;
231 static unsigned $getScale$(NSString *path) {
232 NSString *name(path);
234 #define StripName(strip) \
235 if ([name hasSuffix:@ strip]) \
236 name = [name substringWithRange:NSMakeRange(0, [name length] - sizeof(strip) - 1)];
240 StripName("~iphone");
243 return [name hasSuffix:@"@2x"] ? 2 : 1;
246 static NSArray *$useScale$(NSArray *files, bool use = true) {
247 if (use && Scale_ == 0) {
248 UIScreen *screen([UIScreen mainScreen]);
249 if ([screen respondsToSelector:@selector(scale)])
250 Scale_ = [screen scale];
258 NSString *idiom(IsWild_ ? @"ipad" : @"iphone");
260 NSMutableArray *scaled([NSMutableArray arrayWithCapacity:([files count] * 4)]);
262 for (NSString *file in files) {
263 NSString *base([file stringByDeletingPathExtension]);
264 NSString *extension([file pathExtension]);
268 [scaled addObject:[NSString stringWithFormat:@"%@@2x~%@.%@", base, idiom, extension]];
270 [scaled addObject:[NSString stringWithFormat:@"%@@2x.%@", base, extension]];
273 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
275 // if (!IsWild_) <- support old themes
276 [scaled addObject:file];
277 } else if ([base hasSuffix: @"@2x"]) {
278 [scaled addObject:[NSString stringWithFormat:@"%@~iphone.%@", base, extension]];
279 [scaled addObject:file];
281 // XXX: this actually can't be used, as the person loading the file doesn't realize that the @2x changed
282 /*NSString *rest([base substringWithRange:NSMakeRange(0, [base length] - 3)]);
283 [scaled addObject:[NSString stringWithFormat:@"%@~iphone.%@", rest, extension]];
284 [scaled addObject:[rest stringByAppendingPathExtension:extension]];*/
286 // XXX: this code isn't really complete
288 [scaled addObject:file];
290 if ([base hasSuffix:@"~iphone"])
291 [scaled addObject:[[base substringWithRange:NSMakeRange(0, [base length] - 7)] stringByAppendingPathExtension:extension]];
298 static NSString *$getTheme$(NSArray *files, NSArray *themes = Themes_) {
299 // XXX: this is not reasonable; OMG
302 @synchronized (Themed_) {
303 if (NSString *path = [Themed_ objectForKey:key])
304 return reinterpret_cast<id>(path) == [NSNull null] ? nil : path;
308 NSLog(@"WB:Debug: %@", [files description]);
312 for (NSString *theme in Themes_)
313 for (NSString *file in files) {
314 path = [NSString stringWithFormat:@"%@/%@", theme, file];
315 if ([Manager_ fileExistsAtPath:path])
322 @synchronized (Themed_) {
323 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:key];
329 // $pathForFile$inBundle$() {{{
330 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool ui) {
331 NSString *identifier = [bundle bundleIdentifier];
332 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
334 if (identifier != nil)
335 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
336 if (NSString *folder = [[bundle bundlePath] lastPathComponent]) {
337 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
338 NSString *base([folder stringByDeletingPathExtension]);
339 if ([base hasSuffix:@"~iphone"])
340 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 7)], [folder pathExtension], file]];
343 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
345 #define remapResourceName(oldname, newname) \
346 else if ([file isEqualToString:(oldname)]) \
347 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
349 bool summer(SpringBoard_ && SummerBoard_);
351 if (identifier == nil);
352 else if ([identifier isEqualToString:@"com.apple.chatkit"])
353 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
354 else if ([identifier isEqualToString:@"com.apple.calculator"])
355 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
357 remapResourceName(@"FSO_BG.png", @"StatusBar")
358 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
359 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
361 [names addObject:[NSString stringWithFormat:@"Fallback/%@", file]];
363 if (NSString *path = $getTheme$($useScale$(names, ui)))
370 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
371 NSString *identifier = [self bundleIdentifier];
372 NSString *path = [self path];
373 NSString *folder = [path lastPathComponent];
374 NSString *dname = [self displayName];
375 NSString *didentifier = [self displayIdentifier];
378 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
380 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
382 /* XXX: I might need to keep this for backwards compatibility
383 if (identifier != nil)
384 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
386 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
388 #define testForIcon(Name) \
389 if (NSString *name = Name) \
390 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
392 if (![didentifier isEqualToString:identifier])
393 testForIcon(didentifier);
395 testForIcon(identifier);
398 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
401 if (didentifier != nil) {
402 testForIcon([English_ objectForKey:didentifier]);
404 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
405 if ([parts count] != 1)
406 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
407 testForIcon([english objectForKey:[parts lastObject]]);
410 if (NSString *path = $getTheme$(names))
416 // -[NSBundle wb$bundleWithFile] {{{
417 @interface NSBundle (WinterBoard)
418 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
421 @implementation NSBundle (WinterBoard)
423 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
424 path = [path stringByDeletingLastPathComponent];
425 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
428 NSBundle *bundle([Bundles_ objectForKey:path]);
429 if (reinterpret_cast<id>(bundle) == [NSNull null])
431 else if (bundle == nil) {
432 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
433 bundle = [NSBundle bundleWithPath:path];
435 bundle = [NSBundle wb$bundleWithFile:path];
437 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
438 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
446 // -[NSString wb$themedPath] {{{
447 @interface NSString (WinterBoard)
448 - (NSString *) wb$themedPath;
451 @implementation NSString (WinterBoard)
453 - (NSString *) wb$themedPath {
454 if ([self hasPrefix:@"/Library/Themes/"])
458 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
460 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
461 NSString *file([self stringByResolvingSymlinksInPath]);
462 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
463 if ([file hasPrefix:prefix]) {
464 NSUInteger length([prefix length]);
465 if (length != [file length])
466 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
477 void WBLogRect(const char *tag, struct CGRect rect) {
478 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
481 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
482 CGRect frame([view frame]);
483 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]);
485 for (UIView *child in [view subviews])
486 WBLogHierarchy(child, index++, indent + 1);
489 UIImage *$cacheForImage$(UIImage *image) {
490 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
491 CGRect rect = {CGPointMake(1, 1), [image size]};
492 CGSize size = {rect.size.width + 2, rect.size.height + 2};
494 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
495 CGColorSpaceRelease(space);
497 CGContextDrawImage(context, rect, [image CGImage]);
498 CGImageRef ref(CGBitmapContextCreateImage(context));
499 CGContextRelease(context);
501 UIImage *cache([UIImage imageWithCGImage:ref]);
507 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
508 //if ([name isEqualToString:@"icons"]) return nil;
509 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
512 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
513 NSString *key([icon displayIdentifier]);
515 if (UIImage *image = [icon icon]) {
516 CGSize size = [image size];
517 if (size.width != 59 || size.height != 60) {
518 UIImage *cache($cacheForImage$(image));
519 [Cache_ setObject:cache forKey:key];
524 _SBIconModel$cacheImageForIcon$(self, sel, icon);
527 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
528 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
529 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
531 NSString *key([icon displayIdentifier]);
533 if (UIImage *image = [icon icon]) {
534 CGSize size = [image size];
535 if (size.width != 59 || size.height != 60) {
536 UIImage *cache($cacheForImage$(image));
537 [Cache_ setObject:cache forKey:key];
543 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
544 NSString *key([icon displayIdentifier]);
545 if (UIImage *image = [Cache_ objectForKey:key])
548 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
551 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
553 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
554 NSString *key([icon displayIdentifier]);
555 if (UIImage *image = [Cache_ objectForKey:key])
558 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
561 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
562 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
563 [self setBackgroundColor:[UIColor clearColor]];
564 for (UIView *child in [self subviews])
565 [child setBackgroundColor:[UIColor clearColor]];
569 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
570 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
571 [self setBackgroundColor:[UIColor clearColor]];
575 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
576 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
577 float inset([self edgeInset]);
578 [[UIColor clearColor] set];
579 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
580 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
583 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
584 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
585 if (NSString *path = $pathForIcon$([self application]))
586 return [UIImage imageWithContentsOfFile:path];
587 return _SBApplicationIcon$icon(self, sel);
590 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
592 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
593 if (IsWild_ && false) // XXX: delete this code, it should not be supported
594 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
595 return [UIImage imageWithContentsOfFile:path72];
596 if (NSString *path = $pathForIcon$([self application]))
597 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
599 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
600 width = [$SBIcon defaultIconImageSize].width;
603 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
606 return _SBApplicationIcon$generateIconImage$(self, sel, type);
609 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
611 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
612 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
613 return [UIImage imageWithContentsOfFile:path];
614 return _SBWidgetApplicationIcon$icon(self, sel);
617 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
619 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
620 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
621 return [UIImage imageWithContentsOfFile:path];
622 return _SBBookmarkIcon$icon(self, sel);
625 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
626 if (NSString *path = $pathForIcon$(self))
628 return _SBApplication$pathForIcon(self, sel);
631 static UIImage *CachedImageAtPath(NSString *path) {
632 path = [path stringByResolvingSymlinksInPath];
633 UIImage *image = [PathImages_ objectForKey:path];
635 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
636 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
638 image = [image autorelease];
639 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
643 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
644 NSBundle *bundle = [NSBundle mainBundle];
646 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
647 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
648 return CachedImageAtPath(path);
649 return __UIApplicationImageWithName(name);
652 #define WBDelegate(delegate) \
653 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
655 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
656 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
658 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
662 - (void) forwardInvocation:(NSInvocation*)inv { \
663 SEL sel = [inv selector]; \
664 if ([delegate respondsToSelector:sel]) \
665 [inv invokeWithTarget:delegate]; \
667 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
670 // %hook -[NSBundle pathForResource:ofType:] {{{
671 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
672 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
674 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
675 if (NSString *path = $pathForFile$inBundle$(file, self, false))
677 return MSOldCall(resource, type);
681 static void $drawLabel$(NSString *label, CGRect rect, NSString *style, NSString *custom) {
682 bool ellipsis(false);
683 float max = rect.size.width - 11, width;
685 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
688 size_t length([label length]);
689 float spacing((width - max) / (length - 1));
691 if (spacing > 1.25) {
693 label = [label substringToIndex:(length - 1)];
697 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
701 label = [label stringByAppendingString:@"..."];
704 style = [style stringByAppendingString:custom];
706 CGSize size = [label sizeWithStyle:style forWidth:rect.size.width];
707 [label drawAtPoint:CGPointMake((rect.size.width - size.width) / 2 + rect.origin.x, rect.origin.y) withStyle:style];
710 static struct WBStringDrawingState {
711 WBStringDrawingState *next_;
715 } *stringDrawingState_;
717 MSInstanceMessageHook6(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode,letterSpacing,includeEmoji, CGPoint, point, float, width, UIFont *, font, UILineBreakMode, mode, float, spacing, BOOL, emoji) {
718 //NSLog(@"XXX: @\"%@\" %g", self, spacing);
720 WBStringDrawingState *state(stringDrawingState_);
722 return MSOldCall(point, width, font, mode, spacing, emoji);
724 if (--state->count_ == 0)
725 stringDrawingState_ = state->next_;
726 if (state->info_ == nil)
727 return MSOldCall(point, width, font, mode, spacing, emoji);
729 NSString *info([Info_ objectForKey:state->info_]);
731 return MSOldCall(point, width, font, mode, spacing, emoji);
733 NSString *base(state->base_ ?: @"");
734 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
735 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], extra, base, info]];
739 extern "C" NSString *NSStringFromCGRect(CGRect rect);
741 MSInstanceMessageHook7(CGSize, NSString, _drawInRect,withFont,lineBreakMode,alignment,lineSpacing,includeEmoji,truncationRect, CGRect, rect, UIFont *, font, UILineBreakMode, mode, UITextAlignment, alignment, float, spacing, BOOL, emoji, CGRect, truncation) {
742 //NSLog(@"XXX: &\"%@\" %@ \"%@\" %u %u %g %u %@", self, NSStringFromCGRect(rect), font, mode, alignment, spacing, emoji, NSStringFromCGRect(truncation));
744 WBStringDrawingState *state(stringDrawingState_);
746 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
748 if (--state->count_ == 0)
749 stringDrawingState_ = state->next_;
750 if (state->info_ == nil)
751 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
753 NSString *info([Info_ objectForKey:state->info_]);
755 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
760 case UITextAlignmentLeft:
763 case UITextAlignmentCenter:
764 textAlign = @"center";
766 case UITextAlignmentRight:
767 textAlign = @"right";
771 NSString *base(state->base_ ?: @"");
772 NSString *extra([NSString stringWithFormat:@"text-align: %@", textAlign]);
775 $drawLabel$(self, rect, [NSString stringWithFormat:@"%@;%@", [font markupDescription], base], info);
777 [self drawInRect:rect withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], extra, base, info]];
782 MSInstanceMessageHook4(CGSize, NSString, sizeWithFont,forWidth,lineBreakMode,letterSpacing, UIFont *, font, float, width, UILineBreakMode, mode, float, spacing) {
783 //NSLog(@"XXX: #\"%@\" \"%@\" %g %u %g", self, font, width, mode, spacing);
785 WBStringDrawingState *state(stringDrawingState_);
787 return MSOldCall(font, width, mode, spacing);
789 if (--state->count_ == 0)
790 stringDrawingState_ = state->next_;
791 if (state->info_ == nil)
792 return MSOldCall(font, width, mode, spacing);
794 NSString *info([Info_ objectForKey:state->info_]);
796 return MSOldCall(font, width, mode, spacing);
798 NSString *base(state->base_ ?: @"");
799 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
800 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], extra, base, info] forWidth:width];
803 MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) {
804 //NSLog(@"XXX: ?\"%@\"", self);
806 WBStringDrawingState *state(stringDrawingState_);
808 return MSOldCall(font);
810 if (--state->count_ == 0)
811 stringDrawingState_ = state->next_;
812 if (state->info_ == nil)
813 return MSOldCall(font);
815 NSString *info([Info_ objectForKey:state->info_]);
817 return MSOldCall(font);
819 NSString *base(state->base_ ?: @"");
820 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info] forWidth:65535];
823 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
824 WBStringDrawingState badgeState = {NULL, 1, @""
828 stringDrawingState_ = &badgeState;
830 UIImage *image(MSOldCall(text));
832 stringDrawingState_ = NULL;
836 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
837 WBStringDrawingState dayState = {NULL, 2, @""
839 // XXX: this is only correct on an iPod dock
840 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
841 , @"CalendarIconDayStyle"};
843 WBStringDrawingState sizeState = {&dayState, 7, nil, nil};
845 WBStringDrawingState dateState = {&sizeState, 2, @""
847 , @"CalendarIconDateStyle"};
849 stringDrawingState_ = &dateState;
851 UIImage *image(MSOldCall(type));
853 stringDrawingState_ = NULL;
857 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
858 NSBundle *bundle([NSBundle mainBundle]);
860 CFLocaleRef locale(CFLocaleCopyCurrent());
861 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
864 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
866 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
867 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
868 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
869 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
873 CFRelease(formatter);
875 NSString *datestyle([@""
876 "font-family: Helvetica; "
877 "font-weight: bold; "
880 "" stringByAppendingString:(IsWild_
881 ? @"font-size: 54px; "
882 : @"font-size: 39px; "
885 NSString *daystyle([@""
886 "font-family: Helvetica; "
887 "font-weight: bold; "
889 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
890 "" stringByAppendingString:(IsWild_
891 ? @"font-size: 11px; "
892 : @"font-size: 9px; "
895 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
896 datestyle = [datestyle stringByAppendingString:style];
897 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
898 daystyle = [daystyle stringByAppendingString:style];
900 float width([self bounds].size.width);
902 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
903 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
905 unsigned base0(IsWild_ ? 89 : 70);
906 if ($GSFontGetUseLegacyFontMetrics())
908 unsigned base1(IsWild_ ? 18 : 16);
915 [(NSString *)date drawAtPoint:CGPointMake(
916 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
917 ) withStyle:datestyle];
919 [(NSString *)day drawAtPoint:CGPointMake(
920 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
921 ) withStyle:daystyle];
927 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
928 void $setBarStyle$_(NSString *name, int &style) {
930 NSLog(@"WB:Debug:%@Style:%d", name, style);
931 NSNumber *number = nil;
933 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
935 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
937 style = [number intValue];
939 NSLog(@"WB:Debug:%@Style=%d", name, style);
943 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
944 $setBarStyle$_(@"Toolbar", style);
945 return MSOldCall(style);
948 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
949 $setBarStyle$_(@"NavigationBar", style);
950 return MSOldCall(style);
954 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
955 [[self superview] setBackgroundColor:[UIColor clearColor]];
956 _SBButtonBar$didMoveToSuperview(self, sel);
959 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
960 [[self superview] setBackgroundColor:[UIColor clearColor]];
961 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
964 static NSArray *Wallpapers_;
965 static bool Papered_;
967 static bool SMSBackgrounded_;
968 static NSString *WallpaperFile_;
969 static UIImageView *WallpaperImage_;
970 static UIWebDocumentView *WallpaperPage_;
971 static NSURL *WallpaperURL_;
973 #define _release(object) \
974 do if (object != nil) { \
979 static UIImage *$getImage$(NSString *path) {
980 UIImage *image([UIImage imageWithContentsOfFile:path]);
982 unsigned scale($getScale$(path));
983 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
984 [image setScale:scale];
989 static UIImage *$getDefaultDesktopImage$() {
990 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
991 return $getImage$(path);
995 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
996 return $getDefaultDesktopImage$() ?: MSOldCall();
999 MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
1000 return $getDefaultDesktopImage$() ?: MSOldCall();
1003 MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
1004 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
1005 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
1006 if (UIImage *image = $getDefaultDesktopImage$()) {
1007 [self setImage:image];
1017 // %hook -[SBUIController init] {{{
1018 MSInstanceMessageHook0(id, SBUIController, init) {
1023 NSString *paper($getTheme$(Wallpapers_));
1025 paper = [paper stringByDeletingLastPathComponent];
1029 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
1030 char *machine = new char[size];
1032 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
1033 perror("sysctlbyname(\"hw.machine\", ?)");
1038 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
1042 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
1045 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
1046 if (&_wallpaperView != NULL) {
1047 [_wallpaperView removeFromSuperview];
1048 [_wallpaperView release];
1049 _wallpaperView = nil;
1053 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
1054 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
1057 if (&_contentLayer != NULL)
1058 player = &_contentLayer;
1059 else if (&_contentView != NULL)
1060 player = &_contentView;
1063 UIView *layer(player == NULL ? nil : *player);
1065 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
1066 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
1067 [window setContentView:content];
1069 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
1070 [window setBackgroundColor:[_window backgroundColor]];
1071 [_window setBackgroundColor:[UIColor clearColor]];
1073 [window setLevel:-1000];
1074 [window setHidden:NO];
1076 /*if (player != NULL)
1077 *player = content;*/
1079 [content setBackgroundColor:[layer backgroundColor]];
1080 [layer setBackgroundColor:[UIColor clearColor]];
1083 if (!SummerBoard_ || !IsWild_)
1086 CGRect bounds([content bounds]);
1087 bounds.origin.y = -30;
1088 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
1089 [content addSubview:indirect];
1090 [indirect zoomToScale:2.4];
1093 _release(WallpaperFile_);
1094 _release(WallpaperImage_);
1095 _release(WallpaperPage_);
1096 _release(WallpaperURL_);
1099 NSArray *themes([NSArray arrayWithObject:paper]);
1101 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1105 static AVController *controller_(nil);
1106 if (controller_ == nil) {
1107 AVQueue *queue([AVQueue avQueue]);
1108 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1111 AVQueue *queue([controller_ queue]);
1113 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1114 [controller_ setLayer:[video _layer]];
1116 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1117 [queue appendItem:item error:&error];
1119 [controller_ play:&error];
1120 #elif UseMPMoviePlayerController
1121 NSURL *url([NSURL fileURLWithPath:path]);
1122 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1123 controller.movieControlMode = MPMovieControlModeHidden;
1126 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1127 [video setMovieWithPath:path];
1128 [video setRepeatMode:1];
1129 [video setRepeatGap:-1];
1130 [video playFromBeginning];;
1133 [indirect addSubview:video];
1136 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1137 if (UIImage *image = $getImage$(path)) {
1138 WallpaperFile_ = [path retain];
1139 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1140 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1141 [WallpaperImage_ setAlpha:[number floatValue]];
1142 [indirect addSubview:WallpaperImage_];
1146 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1147 CGRect bounds = [indirect bounds];
1149 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1150 [view setAutoresizes:true];
1152 WallpaperPage_ = [view retain];
1153 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1155 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1157 [view setBackgroundColor:[UIColor clearColor]];
1158 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1159 [view setDrawsBackground:NO];
1160 [[view webView] setDrawsBackground:NO];
1162 [indirect addSubview:view];
1166 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1167 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1168 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1169 if ([Manager_ fileExistsAtPath:html]) {
1170 CGRect bounds = [indirect bounds];
1172 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1173 [view setAutoresizes:true];
1175 NSURL *url = [NSURL fileURLWithPath:html];
1176 [view loadRequest:[NSURLRequest requestWithURL:url]];
1178 [view setBackgroundColor:[UIColor clearColor]];
1179 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1180 [view setDrawsBackground:NO];
1181 [[view webView] setDrawsBackground:NO];
1183 [indirect addSubview:view];
1191 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1192 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1193 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1195 if (path != nil && _backgroundView != nil)
1198 _SBAwayView$updateDesktopImage$(self, sel, image);
1201 CGRect bounds = [self bounds];
1203 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1204 [view setAutoresizes:true];
1206 if (WallpaperPage_ != nil)
1207 [WallpaperPage_ release];
1208 WallpaperPage_ = [view retain];
1210 if (WallpaperURL_ != nil)
1211 [WallpaperURL_ release];
1212 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1214 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1216 [[view webView] setDrawsBackground:false];
1217 [view setBackgroundColor:[UIColor clearColor]];
1219 [self insertSubview:view aboveSubview:_backgroundView];
1223 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1224 extern "C" CGColorRef CGGStateGetFillColor(void *);
1225 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1226 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1228 /* WBTimeLabel {{{ */
1229 @interface WBTimeLabel : NSProxy {
1231 _transient SBStatusBarTimeView *view_;
1234 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1238 @implementation WBTimeLabel
1245 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1246 time_ = [time retain];
1251 - (NSString *) description {
1257 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1258 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1259 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1261 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1262 "font-family: Helvetica; "
1263 "font-weight: bold; "
1266 "%@", _mode ? @"white" : @"black", custom]];
1271 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1276 /* WBBadgeLabel {{{ */
1277 @interface WBBadgeLabel : NSProxy {
1281 - (id) initWithBadge:(NSString *)badge;
1282 - (NSString *) description;
1286 @implementation WBBadgeLabel
1293 - (id) initWithBadge:(NSString *)badge {
1294 badge_ = [badge retain];
1298 - (NSString *) description {
1299 return [badge_ description];
1304 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1305 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1306 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1307 "font-family: Helvetica; "
1308 "font-weight: bold; "
1316 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1323 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1324 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1325 alpha = [number floatValue];
1326 return MSOldCall(alpha);
1329 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1330 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1331 alpha = [number floatValue];
1332 return MSOldCall(alpha);
1335 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1336 if ((self = MSOldCall()) != nil) {
1337 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1338 // XXX: note: this is overridden above, which is silly
1339 float alpha([number floatValue]);
1340 [self setIconImageAlpha:alpha];
1341 [self setIconLabelAlpha:alpha];
1346 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1347 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1348 alpha = [number floatValue];
1349 return MSOldCall(alpha);
1353 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1354 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1355 id &_badge(MSHookIvar<id>(self, "_badge"));
1357 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1362 void SBStatusBarController$setStatusBarMode(int &mode) {
1364 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1365 if (mode < 100) // 104:hidden 105:glowing
1366 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1367 mode = [number intValue];
1370 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1371 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1372 SBStatusBarController$setStatusBarMode(mode);
1373 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1376 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1377 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1378 SBStatusBarController$setStatusBarMode(mode);
1379 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1382 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) {
1383 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1384 SBStatusBarController$setStatusBarMode(mode);
1385 //NSLog(@"mode=%u", mode);
1386 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1389 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1390 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1391 mode = [number intValue];
1392 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1395 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1396 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1398 NSLog(@"operatorNameStyle= %@", style);
1399 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1400 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1404 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1406 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1407 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1410 // XXX: replace this with [SBStatusBarTimeView tile]
1411 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1412 id &_time(MSHookIvar<id>(self, "_time"));
1413 if (_time != nil && [_time class] != [WBTimeLabel class])
1414 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1415 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1418 @interface UIView (WinterBoard)
1419 - (bool) wb$isWBImageView;
1420 - (void) wb$logHierarchy;
1421 - (void) wb$setBackgroundColor:(UIColor *)color;
1424 @implementation UIView (WinterBoard)
1426 - (bool) wb$isWBImageView {
1430 - (void) wb$logHierarchy {
1431 WBLogHierarchy(self);
1434 - (void) wb$setBackgroundColor:(UIColor *)color {
1435 [self setBackgroundColor:color];
1436 for (UIView *child in [self subviews])
1437 [child wb$setBackgroundColor:color];
1442 @interface WBImageView : UIImageView {
1445 - (bool) wb$isWBImageView;
1446 - (void) wb$updateFrame;
1449 @implementation WBImageView
1451 - (bool) wb$isWBImageView {
1455 - (void) wb$updateFrame {
1456 CGRect frame([self frame]);
1459 for (UIView *view(self); ; ) {
1460 view = [view superview];
1463 frame.origin.y -= [view frame].origin.y;
1466 [self setFrame:frame];
1471 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1472 NSArray *subviews([self subviews]);
1473 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1474 if (view != nil && [view wb$isWBImageView])
1475 [view wb$updateFrame];
1476 _SBIconList$setFrame$(self, sel, frame);
1479 static void $addPerPageView$(unsigned i, UIView *list) {
1480 NSString *path($getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", 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 static void $addPerPageViews$(NSArray *lists) {
1503 for (unsigned i(0), e([lists count]); i != e; ++i)
1504 $addPerPageView$(i, [lists objectAtIndex:i]);
1507 MSInstanceMessageHook0(void, SBIconController, updateNumberOfRootIconLists) {
1508 NSArray *&_rootIconLists(MSHookIvar<NSArray *>(self, "_rootIconLists"));
1509 $addPerPageViews$(_rootIconLists);
1513 MSInstanceMessageHook0(void, SBIconContentView, layoutSubviews) {
1516 if (SBIconController *controller = [$SBIconController sharedInstance]) {
1517 UIView *&_dockContainerView(MSHookIvar<UIView *>(controller, "_dockContainerView"));
1518 if (&_dockContainerView != NULL)
1519 [[_dockContainerView superview] bringSubviewToFront:_dockContainerView];
1523 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1524 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1525 $addPerPageViews$([_iconModel iconLists]);
1526 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1529 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1530 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1532 [self setClipsToBounds:NO];
1536 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1537 static bool gssc(false);
1539 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1540 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1543 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1544 [Info_ setObject:[NSNumber numberWithBool:(
1546 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1547 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1548 )] forKey:@"UndockedIconLabels"];
1551 id &_label(MSHookIvar<id>(self, "_label"));
1552 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1555 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1556 [_label setInDock:docked];
1558 _SBIconLabel$setInDock$(self, sel, docked);
1559 [self setNeedsDisplay];
1562 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1563 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1566 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1567 _SBDockIconListView$setFrame$(self, sel, frame);
1570 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1571 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1572 NSString *identifier = [self bundleIdentifier];
1573 NSLocale *locale = [NSLocale currentLocale];
1574 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1576 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1577 NSString *file = table == nil ? @"Localizable" : table;
1578 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1579 NSDictionary *strings;
1580 if ((strings = [Strings_ objectForKey:name]) != nil) {
1581 if (static_cast<id>(strings) != [NSNull null]) strings:
1582 if (NSString *value = [strings objectForKey:key])
1584 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1587 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1588 [Strings_ setObject:[strings autorelease] forKey:name];
1592 [Strings_ setObject:[NSNull null] forKey:name];
1593 return MSOldCall(key, value, table);
1596 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1597 MSClassHook(WebCoreFrameBridge)
1599 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1602 void **core(reinterpret_cast<void **>([node _node]));
1603 if (core == NULL || core[6] == NULL)
1605 return MSOldCall(node, width);
1609 MSInstanceMessage1(void, SBIconLabel, drawRect, CGRect, rect) {
1610 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1613 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1614 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1616 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1618 NSString *style = [NSString stringWithFormat:@""
1619 "font-family: Helvetica; "
1620 "font-weight: bold; "
1622 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1623 ? @"font-size: 12px; "
1624 : @"font-size: 11px; "
1628 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1630 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1632 NSString *custom([Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")]);
1634 $drawLabel$(label, [self bounds], style, custom);
1637 MSInstanceMessage0(CGImageRef, SBIconLabel, buildLabelImage) {
1638 bool docked((MSHookIvar<unsigned>(self, "_inDock") & 0x2) != 0);
1640 WBStringDrawingState labelState = {NULL, 0, @""
1642 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1644 stringDrawingState_ = &labelState;
1647 CGImageRef image(MSOldCall());
1650 stringDrawingState_ = NULL;
1655 MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1656 if ((self = MSOldCall(frame, delegate)) != nil) {
1657 [self setBackgroundColor:[UIColor clearColor]];
1661 MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1662 return SMSBackgrounded_ ? NO : MSOldCall();
1665 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1666 [self wb$setBackgroundColor:[UIColor clearColor]];
1670 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1672 [balloon setBackgroundColor:[UIColor clearColor]];
1675 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1676 MSOldCall([UIColor clearColor]);
1677 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1681 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1682 if ((self = MSOldCall(style, reuse)) != nil) {
1683 [self setBackgroundColor:[UIColor clearColor]];
1684 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1689 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1690 if ((self = MSOldCall(style, reuse)) != nil) {
1691 [self setBackgroundColor:[UIColor clearColor]];
1692 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1696 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1697 if ((self = MSOldCall(style, reuse)) != nil) {
1698 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1699 [_label setBackgroundColor:[UIColor clearColor]];
1703 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1704 MSOldCall(UITableViewCellSeparatorStyleNone);
1707 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1708 if ((self = MSOldCall(frame, style)) != nil) {
1709 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1713 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1716 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1717 if (UIImage *image = $getImage$(path)) {
1718 SMSBackgrounded_ = true;
1720 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1721 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1723 if (&_transcriptTable != NULL)
1724 table = _transcriptTable;
1725 else if (&_transcriptLayer != NULL)
1726 table = _transcriptLayer;
1730 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1731 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1734 [placard insertSubview:background atIndex:0];
1736 [table setBackgroundColor:[UIColor clearColor]];
1737 [placard insertSubview:background belowSubview:table];
1743 // %hook _UIImageWithName() {{{
1744 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1746 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1753 if (_UIPackedImageTableGetIdentifierForName != NULL)
1754 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1755 else if (_UISharedImageNameGetIdentifier != NULL) {
1756 identifier = _UISharedImageNameGetIdentifier(name);
1757 packed = identifier != -1;
1764 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1767 return __UIImageWithName(name);
1769 NSNumber *key([NSNumber numberWithInt:identifier]);
1770 UIImage *image([UIImages_ objectForKey:key]);
1772 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1773 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1774 image = $getImage$(path);
1775 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1779 image = __UIImageWithName(name);
1782 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1783 if (![Manager_ fileExistsAtPath:path])
1784 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1791 // %hook _UIImageWithNameInDomain() {{{
1792 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1793 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1794 UIImage *image([PathImages_ objectForKey:key]);
1796 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1798 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1799 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1800 image = $getImage$(path);
1801 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1802 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1806 // %hook GSFontCreateWithName() {{{
1807 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1809 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1810 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1811 name = [font UTF8String];
1812 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1813 // size *= [scale floatValue];
1814 return _GSFontCreateWithName(name, traits, size);
1818 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1819 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1821 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1823 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1825 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1826 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1828 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1831 NSString *path = [NSString stringWithUTF8String:a1];
1832 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1833 NSString *file = [path substringFromIndex:31];
1834 for (NSString *theme in Themes_) {
1835 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1836 if ([Manager_ fileExistsAtPath:path]) {
1837 strcpy(a1, [path UTF8String]);
1846 static void ChangeWallpaper(
1847 CFNotificationCenterRef center,
1851 CFDictionaryRef info
1854 NSLog(@"WB:Debug:ChangeWallpaper!");
1857 if (WallpaperFile_ != nil) {
1858 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1860 image = [image autorelease];
1863 if (WallpaperImage_ != nil)
1864 [WallpaperImage_ setImage:image];
1865 if (WallpaperPage_ != nil)
1866 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1870 #define WBRename(name, sel, imp) \
1871 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
1873 template <typename Type_>
1874 static void msset(Type_ &function, MSImageRef image, const char *name) {
1875 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1878 template <typename Type_>
1879 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1880 struct nlist &name(nl[index]);
1881 uintptr_t value(name.n_value);
1882 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1883 value |= 0x00000001;
1884 function = reinterpret_cast<Type_>(value);
1887 template <typename Type_>
1888 static void dlset(Type_ &function, const char *name) {
1889 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1892 // %hook CGImageReadCreateWithFile() {{{
1893 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1895 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1896 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1897 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1903 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
1904 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1905 if (style == nil || [style length] == 0)
1906 style = @"font-family: Helvetica; font-size: 12px";
1907 //NSLog(@"XXX:draw(%@)", [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
1908 return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
1911 static void NSString$drawInRect$withStyle$(NSString *self, SEL _cmd, CGRect rect, NSString *style) {
1912 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1913 if (style == nil || [style length] == 0)
1914 style = @"font-family: Helvetica; font-size: 12px";
1915 return [[WBMarkup sharedMarkup] drawString:self inRect:rect withStyle:style];
1918 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
1919 if (style == nil || [style length] == 0)
1920 style = @"font-family: Helvetica; font-size: 12px";
1921 //NSLog(@"XXX:size(%@)", [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
1922 return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width];
1925 static void SBInitialize() {
1926 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
1927 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v28@0:4{CGRect={CGSize=ff}{CGSize=ff}}8@24");
1928 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
1931 WBRename(SBApplication, pathForIcon, pathForIcon);
1932 WBRename(SBApplicationIcon, icon, icon);
1933 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1936 WBRename(SBBookmarkIcon, icon, icon);
1937 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1938 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1939 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1940 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
1942 WBRename(SBWidgetApplicationIcon, icon, icon);
1944 WBRename(SBDockIconListView, setFrame:, setFrame$);
1945 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
1947 if (kCFCoreFoundationVersionNumber < 600 || SummerBoard_)
1948 WBRename(SBIconLabel, drawRect:, drawRect$);
1950 WBRename(SBIconLabel, buildLabelImage, buildLabelImage);
1952 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
1953 WBRename(SBIconLabel, setInDock:, setInDock$);
1955 WBRename(SBIconList, setFrame:, setFrame$);
1957 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
1958 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
1959 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
1960 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
1962 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
1963 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
1964 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
1966 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
1968 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
1969 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
1970 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
1971 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
1972 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
1973 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
1974 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
1975 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
1976 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
1979 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
1983 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1985 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
1986 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
1988 Manager_ = [[NSFileManager defaultManager] retain];
1989 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
1991 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
1993 // Load Settings.plist {{{
1994 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
1995 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
1996 SummerBoard_ = [value boolValue];
1998 SummerBoard_ = true;
2000 if (NSNumber *value = [settings objectForKey:@"Debug"])
2001 Debug_ = [value boolValue];
2002 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
2003 UIDebug_ = [value boolValue];
2005 NSArray *themes([settings objectForKey:@"Themes"]);
2007 if (NSString *theme = [settings objectForKey:@"Theme"])
2008 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
2010 [NSNumber numberWithBool:true], @"Active",
2014 for (NSDictionary *theme in themes) {
2015 NSNumber *active([theme objectForKey:@"Active"]);
2016 if (![active boolValue])
2019 NSString *name([theme objectForKey:@"Name"]);
2023 NSString *theme(nil);
2025 #define testForTheme(format...) \
2026 if (theme == nil) { \
2027 NSString *path = [NSString stringWithFormat:format]; \
2028 if ([Manager_ fileExistsAtPath:path]) { \
2029 [Themes_ addObject:path]; \
2034 testForTheme(@"/Library/Themes/%@.theme", name)
2035 testForTheme(@"/Library/Themes/%@", name)
2036 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
2041 // Merge Info.plist {{{
2042 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2044 for (NSString *theme in Themes_)
2045 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
2046 for (NSString *key in [info allKeys])
2047 if ([Info_ objectForKey:key] == nil)
2048 [Info_ setObject:[info objectForKey:key] forKey:key];
2052 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
2053 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
2054 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
2057 // GraphicsServices {{{
2059 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
2063 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
2064 void *(*CGImageReadCreateWithFile)(NSString *, int);
2065 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
2066 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
2071 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
2072 Papered_ = $getTheme$(Wallpapers_) != nil;
2073 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
2075 CFNotificationCenterAddObserver(
2076 CFNotificationCenterGetDarwinNotifyCenter(),
2077 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
2080 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
2081 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
2082 if (MediaPlayer != nil)
2085 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
2086 $MPVideoView = objc_getClass("MPVideoView");
2093 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
2095 memset(nl, 0, sizeof(nl));
2096 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
2097 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
2098 nl[2].n_un.n_name = (char *) "__UIKitBundle";
2099 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
2100 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
2103 nlset(_UIApplicationImageWithName, nl, 0);
2104 nlset(_UIImageWithNameInDomain, nl, 1);
2105 nlset(_UIKitBundle, nl, 2);
2106 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
2107 nlset(_UISharedImageNameGetIdentifier, nl, 4);
2109 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
2110 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
2111 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
2115 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
2116 NSError *error(nil);
2117 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
2118 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
2120 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);