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 if ([self respondsToSelector:@selector(setIconImageAlpha:)])
1341 [self setIconImageAlpha:alpha];
1342 if ([self respondsToSelector:@selector(setIconLabelAlpha:)])
1343 [self setIconLabelAlpha:alpha];
1344 if ([self respondsToSelector:@selector(setAlpha:)])
1345 [self setAlpha:alpha];
1350 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1351 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1352 alpha = [number floatValue];
1353 return MSOldCall(alpha);
1357 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1358 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1359 id &_badge(MSHookIvar<id>(self, "_badge"));
1361 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1366 void SBStatusBarController$setStatusBarMode(int &mode) {
1368 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1369 if (mode < 100) // 104:hidden 105:glowing
1370 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1371 mode = [number intValue];
1374 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1375 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1376 SBStatusBarController$setStatusBarMode(mode);
1377 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1380 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1381 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1382 SBStatusBarController$setStatusBarMode(mode);
1383 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1386 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) {
1387 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1388 SBStatusBarController$setStatusBarMode(mode);
1389 //NSLog(@"mode=%u", mode);
1390 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1393 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1394 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1395 mode = [number intValue];
1396 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1399 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1400 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1402 NSLog(@"operatorNameStyle= %@", style);
1403 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1404 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1408 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1410 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1411 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1414 // XXX: replace this with [SBStatusBarTimeView tile]
1415 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1416 id &_time(MSHookIvar<id>(self, "_time"));
1417 if (_time != nil && [_time class] != [WBTimeLabel class])
1418 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1419 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1422 @interface UIView (WinterBoard)
1423 - (bool) wb$isWBImageView;
1424 - (void) wb$logHierarchy;
1425 - (void) wb$setBackgroundColor:(UIColor *)color;
1428 @implementation UIView (WinterBoard)
1430 - (bool) wb$isWBImageView {
1434 - (void) wb$logHierarchy {
1435 WBLogHierarchy(self);
1438 - (void) wb$setBackgroundColor:(UIColor *)color {
1439 [self setBackgroundColor:color];
1440 for (UIView *child in [self subviews])
1441 [child wb$setBackgroundColor:color];
1446 @interface WBImageView : UIImageView {
1449 - (bool) wb$isWBImageView;
1450 - (void) wb$updateFrame;
1453 @implementation WBImageView
1455 - (bool) wb$isWBImageView {
1459 - (void) wb$updateFrame {
1460 CGRect frame([self frame]);
1463 for (UIView *view(self); ; ) {
1464 view = [view superview];
1467 frame.origin.y -= [view frame].origin.y;
1470 [self setFrame:frame];
1475 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1476 NSArray *subviews([self subviews]);
1477 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1478 if (view != nil && [view wb$isWBImageView])
1479 [view wb$updateFrame];
1480 _SBIconList$setFrame$(self, sel, frame);
1483 static void $addPerPageView$(unsigned i, UIView *list) {
1484 NSString *path($getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]]));
1488 NSArray *subviews([list subviews]);
1490 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1491 if (view == nil || ![view wb$isWBImageView]) {
1492 view = [[[WBImageView alloc] init] autorelease];
1493 [list insertSubview:view atIndex:0];
1496 UIImage *image([UIImage imageWithContentsOfFile:path]);
1498 CGRect frame([view frame]);
1499 frame.size = [image size];
1500 [view setFrame:frame];
1502 [view setImage:image];
1503 [view wb$updateFrame];
1506 static void $addPerPageViews$(NSArray *lists) {
1507 for (unsigned i(0), e([lists count]); i != e; ++i)
1508 $addPerPageView$(i, [lists objectAtIndex:i]);
1511 MSInstanceMessageHook0(void, SBIconController, updateNumberOfRootIconLists) {
1512 NSArray *&_rootIconLists(MSHookIvar<NSArray *>(self, "_rootIconLists"));
1513 $addPerPageViews$(_rootIconLists);
1517 MSInstanceMessageHook0(void, SBIconContentView, layoutSubviews) {
1520 if (SBIconController *controller = [$SBIconController sharedInstance]) {
1521 UIView *&_dockContainerView(MSHookIvar<UIView *>(controller, "_dockContainerView"));
1522 if (&_dockContainerView != NULL)
1523 [[_dockContainerView superview] bringSubviewToFront:_dockContainerView];
1527 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1528 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1529 $addPerPageViews$([_iconModel iconLists]);
1530 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1533 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1534 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1536 [self setClipsToBounds:NO];
1540 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1541 static bool gssc(false);
1543 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1544 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1547 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1548 [Info_ setObject:[NSNumber numberWithBool:(
1550 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1551 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1552 )] forKey:@"UndockedIconLabels"];
1555 id &_label(MSHookIvar<id>(self, "_label"));
1556 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1559 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1560 [_label setInDock:docked];
1562 _SBIconLabel$setInDock$(self, sel, docked);
1563 [self setNeedsDisplay];
1566 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1567 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1570 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1571 _SBDockIconListView$setFrame$(self, sel, frame);
1574 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1575 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1576 NSString *identifier = [self bundleIdentifier];
1577 NSLocale *locale = [NSLocale currentLocale];
1578 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1580 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1581 NSString *file = table == nil ? @"Localizable" : table;
1582 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1583 NSDictionary *strings;
1584 if ((strings = [Strings_ objectForKey:name]) != nil) {
1585 if (static_cast<id>(strings) != [NSNull null]) strings:
1586 if (NSString *value = [strings objectForKey:key])
1588 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1591 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1592 [Strings_ setObject:[strings autorelease] forKey:name];
1596 [Strings_ setObject:[NSNull null] forKey:name];
1597 return MSOldCall(key, value, table);
1600 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1601 MSClassHook(WebCoreFrameBridge)
1603 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1606 void **core(reinterpret_cast<void **>([node _node]));
1607 if (core == NULL || core[6] == NULL)
1609 return MSOldCall(node, width);
1613 MSInstanceMessage1(void, SBIconLabel, drawRect, CGRect, rect) {
1614 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1617 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1618 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1620 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1622 NSString *style = [NSString stringWithFormat:@""
1623 "font-family: Helvetica; "
1624 "font-weight: bold; "
1626 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1627 ? @"font-size: 12px; "
1628 : @"font-size: 11px; "
1632 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1634 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1636 NSString *custom([Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")]);
1638 $drawLabel$(label, [self bounds], style, custom);
1641 MSInstanceMessage0(CGImageRef, SBIconLabel, buildLabelImage) {
1642 bool docked((MSHookIvar<unsigned>(self, "_inDock") & 0x2) != 0);
1644 WBStringDrawingState labelState = {NULL, 0, @""
1646 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1648 stringDrawingState_ = &labelState;
1651 CGImageRef image(MSOldCall());
1654 stringDrawingState_ = NULL;
1659 MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1660 if ((self = MSOldCall(frame, delegate)) != nil) {
1661 [self setBackgroundColor:[UIColor clearColor]];
1665 MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1666 return SMSBackgrounded_ ? NO : MSOldCall();
1669 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1670 [self wb$setBackgroundColor:[UIColor clearColor]];
1674 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1676 [balloon setBackgroundColor:[UIColor clearColor]];
1679 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1680 MSOldCall([UIColor clearColor]);
1681 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1685 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1686 if ((self = MSOldCall(style, reuse)) != nil) {
1687 [self setBackgroundColor:[UIColor clearColor]];
1688 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1693 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1694 if ((self = MSOldCall(style, reuse)) != nil) {
1695 [self setBackgroundColor:[UIColor clearColor]];
1696 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1700 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1701 if ((self = MSOldCall(style, reuse)) != nil) {
1702 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1703 [_label setBackgroundColor:[UIColor clearColor]];
1707 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1708 MSOldCall(UITableViewCellSeparatorStyleNone);
1711 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1712 if ((self = MSOldCall(frame, style)) != nil) {
1713 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1717 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1720 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1721 if (UIImage *image = $getImage$(path)) {
1722 SMSBackgrounded_ = true;
1724 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1725 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1727 if (&_transcriptTable != NULL)
1728 table = _transcriptTable;
1729 else if (&_transcriptLayer != NULL)
1730 table = _transcriptLayer;
1734 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1735 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1738 [placard insertSubview:background atIndex:0];
1740 [table setBackgroundColor:[UIColor clearColor]];
1741 [placard insertSubview:background belowSubview:table];
1747 // %hook _UIImageWithName() {{{
1748 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1750 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1757 if (_UIPackedImageTableGetIdentifierForName != NULL)
1758 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1759 else if (_UISharedImageNameGetIdentifier != NULL) {
1760 identifier = _UISharedImageNameGetIdentifier(name);
1761 packed = identifier != -1;
1768 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1771 return __UIImageWithName(name);
1773 NSNumber *key([NSNumber numberWithInt:identifier]);
1774 UIImage *image([UIImages_ objectForKey:key]);
1776 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1777 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1778 image = $getImage$(path);
1779 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1783 image = __UIImageWithName(name);
1786 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1787 if (![Manager_ fileExistsAtPath:path])
1788 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1795 // %hook _UIImageWithNameInDomain() {{{
1796 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1797 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1798 UIImage *image([PathImages_ objectForKey:key]);
1800 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1802 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1803 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1804 image = $getImage$(path);
1805 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1806 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1810 // %hook GSFontCreateWithName() {{{
1811 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1813 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1814 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1815 name = [font UTF8String];
1816 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1817 // size *= [scale floatValue];
1818 return _GSFontCreateWithName(name, traits, size);
1822 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1823 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1825 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1827 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1829 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1830 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1832 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1835 NSString *path = [NSString stringWithUTF8String:a1];
1836 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1837 NSString *file = [path substringFromIndex:31];
1838 for (NSString *theme in Themes_) {
1839 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1840 if ([Manager_ fileExistsAtPath:path]) {
1841 strcpy(a1, [path UTF8String]);
1850 static void ChangeWallpaper(
1851 CFNotificationCenterRef center,
1855 CFDictionaryRef info
1858 NSLog(@"WB:Debug:ChangeWallpaper!");
1861 if (WallpaperFile_ != nil) {
1862 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1864 image = [image autorelease];
1867 if (WallpaperImage_ != nil)
1868 [WallpaperImage_ setImage:image];
1869 if (WallpaperPage_ != nil)
1870 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1874 #define WBRename(name, sel, imp) \
1875 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
1877 template <typename Type_>
1878 static void msset(Type_ &function, MSImageRef image, const char *name) {
1879 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1882 template <typename Type_>
1883 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1884 struct nlist &name(nl[index]);
1885 uintptr_t value(name.n_value);
1886 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1887 value |= 0x00000001;
1888 function = reinterpret_cast<Type_>(value);
1891 template <typename Type_>
1892 static void dlset(Type_ &function, const char *name) {
1893 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1896 // %hook CGImageReadCreateWithFile() {{{
1897 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1899 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1900 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1901 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1907 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
1908 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1909 if (style == nil || [style length] == 0)
1910 style = @"font-family: Helvetica; font-size: 12px";
1911 //NSLog(@"XXX:draw(%@)", [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
1912 return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
1915 static void NSString$drawInRect$withStyle$(NSString *self, SEL _cmd, CGRect rect, NSString *style) {
1916 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1917 if (style == nil || [style length] == 0)
1918 style = @"font-family: Helvetica; font-size: 12px";
1919 return [[WBMarkup sharedMarkup] drawString:self inRect:rect withStyle:style];
1922 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
1923 if (style == nil || [style length] == 0)
1924 style = @"font-family: Helvetica; font-size: 12px";
1925 //NSLog(@"XXX:size(%@)", [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
1926 return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width];
1929 static void SBInitialize() {
1930 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
1931 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v28@0:4{CGRect={CGSize=ff}{CGSize=ff}}8@24");
1932 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
1935 WBRename(SBApplication, pathForIcon, pathForIcon);
1936 WBRename(SBApplicationIcon, icon, icon);
1937 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1940 WBRename(SBBookmarkIcon, icon, icon);
1941 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1942 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1943 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1944 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
1946 WBRename(SBWidgetApplicationIcon, icon, icon);
1948 WBRename(SBDockIconListView, setFrame:, setFrame$);
1949 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
1951 if (kCFCoreFoundationVersionNumber < 600 || SummerBoard_)
1952 WBRename(SBIconLabel, drawRect:, drawRect$);
1954 WBRename(SBIconLabel, buildLabelImage, buildLabelImage);
1956 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
1957 WBRename(SBIconLabel, setInDock:, setInDock$);
1959 WBRename(SBIconList, setFrame:, setFrame$);
1961 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
1962 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
1963 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
1964 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
1966 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
1967 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
1968 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
1970 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
1972 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
1973 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
1974 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
1975 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
1976 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
1977 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
1978 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
1979 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
1980 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
1983 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
1987 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1989 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
1990 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
1992 Manager_ = [[NSFileManager defaultManager] retain];
1993 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
1995 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
1997 // Load Settings.plist {{{
1998 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
1999 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
2000 SummerBoard_ = [value boolValue];
2002 SummerBoard_ = true;
2004 if (NSNumber *value = [settings objectForKey:@"Debug"])
2005 Debug_ = [value boolValue];
2006 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
2007 UIDebug_ = [value boolValue];
2009 NSArray *themes([settings objectForKey:@"Themes"]);
2011 if (NSString *theme = [settings objectForKey:@"Theme"])
2012 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
2014 [NSNumber numberWithBool:true], @"Active",
2018 for (NSDictionary *theme in themes) {
2019 NSNumber *active([theme objectForKey:@"Active"]);
2020 if (![active boolValue])
2023 NSString *name([theme objectForKey:@"Name"]);
2027 NSString *theme(nil);
2029 #define testForTheme(format...) \
2030 if (theme == nil) { \
2031 NSString *path = [NSString stringWithFormat:format]; \
2032 if ([Manager_ fileExistsAtPath:path]) { \
2033 [Themes_ addObject:path]; \
2038 testForTheme(@"/Library/Themes/%@.theme", name)
2039 testForTheme(@"/Library/Themes/%@", name)
2040 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
2045 // Merge Info.plist {{{
2046 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2048 for (NSString *theme in Themes_)
2049 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
2050 for (NSString *key in [info allKeys])
2051 if ([Info_ objectForKey:key] == nil)
2052 [Info_ setObject:[info objectForKey:key] forKey:key];
2056 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
2057 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
2058 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
2061 // GraphicsServices {{{
2063 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
2067 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
2068 void *(*CGImageReadCreateWithFile)(NSString *, int);
2069 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
2070 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
2075 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
2076 Papered_ = $getTheme$(Wallpapers_) != nil;
2077 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
2079 CFNotificationCenterAddObserver(
2080 CFNotificationCenterGetDarwinNotifyCenter(),
2081 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
2084 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
2085 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
2086 if (MediaPlayer != nil)
2089 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
2090 $MPVideoView = objc_getClass("MPVideoView");
2097 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
2099 memset(nl, 0, sizeof(nl));
2100 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
2101 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
2102 nl[2].n_un.n_name = (char *) "__UIKitBundle";
2103 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
2104 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
2107 nlset(_UIApplicationImageWithName, nl, 0);
2108 nlset(_UIImageWithNameInDomain, nl, 1);
2109 nlset(_UIKitBundle, nl, 2);
2110 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
2111 nlset(_UISharedImageNameGetIdentifier, nl, 4);
2113 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
2114 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
2115 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
2119 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
2120 NSError *error(nil);
2121 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
2122 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
2124 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);