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)
124 MSClassHook(UIStatusBarTimeItemView)
126 MSClassHook(CKBalloonView)
127 MSClassHook(CKMessageCell)
128 MSClassHook(CKTimestampView)
129 MSClassHook(CKTranscriptCell)
130 MSClassHook(CKTranscriptController)
131 MSClassHook(CKTranscriptHeaderView)
132 MSClassHook(CKTranscriptTableView)
134 MSClassHook(SBApplication)
135 MSClassHook(SBApplicationIcon)
136 MSClassHook(SBAwayView)
137 MSClassHook(SBBookmarkIcon)
138 MSClassHook(SBButtonBar)
139 MSClassHook(SBCalendarApplicationIcon)
140 MSClassHook(SBCalendarIconContentsView)
141 MSClassHook(SBDockIconListView)
143 MSClassHook(SBIconBadge)
144 MSClassHook(SBIconBadgeFactory)
145 MSClassHook(SBIconContentView)
146 MSClassHook(SBIconController)
147 MSClassHook(SBIconLabel)
148 MSClassHook(SBIconList)
149 MSClassHook(SBIconModel)
150 //MSClassHook(SBImageCache)
151 MSClassHook(SBSearchView)
152 MSClassHook(SBSearchTableViewCell)
153 MSClassHook(SBSlidingAlertDisplay)
154 MSClassHook(SBStatusBarContentsView)
155 MSClassHook(SBStatusBarController)
156 MSClassHook(SBStatusBarOperatorNameView)
157 MSClassHook(SBStatusBarTimeView)
158 MSClassHook(SBUIController)
159 MSClassHook(SBWallpaperView)
160 MSClassHook(SBWidgetApplicationIcon)
162 extern "C" void WKSetCurrentGraphicsContext(CGContextRef);
164 static struct MSFixClass { MSFixClass() {
165 $SBIcon = objc_getClass("SBIconView") ?: $SBIcon;
167 if ($SBIconList == nil)
168 $SBIconList = objc_getClass("SBIconListView");
169 if ($CKTranscriptController == nil)
170 $CKTranscriptController = objc_getClass("mSMSMessageTranscriptController");
174 static bool Four_($SBDockIconListView != nil);
176 @interface NSDictionary (WinterBoard)
177 - (UIColor *) wb$colorForKey:(NSString *)key;
178 - (BOOL) wb$boolForKey:(NSString *)key;
181 @implementation NSDictionary (WinterBoard)
183 - (UIColor *) wb$colorForKey:(NSString *)key {
184 NSString *value = [self objectForKey:key];
191 - (BOOL) wb$boolForKey:(NSString *)key {
192 if (NSString *value = [self objectForKey:key])
193 return [value boolValue];
199 static BOOL (*_GSFontGetUseLegacyFontMetrics)();
200 #define $GSFontGetUseLegacyFontMetrics() \
201 (_GSFontGetUseLegacyFontMetrics == NULL ? YES : _GSFontGetUseLegacyFontMetrics())
203 static bool Debug_ = false;
204 static bool UIDebug_ = false;
205 static bool Engineer_ = false;
206 static bool SummerBoard_ = false;
207 static bool SpringBoard_;
209 static UIImage *(*_UIApplicationImageWithName)(NSString *name);
210 static UIImage *(*_UIImageWithNameInDomain)(NSString *name, NSString *domain);
211 static NSBundle *(*_UIKitBundle)();
212 static bool (*_UIPackedImageTableGetIdentifierForName)(NSString *, int *);
213 static int (*_UISharedImageNameGetIdentifier)(NSString *);
215 static NSMutableDictionary *UIImages_ = [[NSMutableDictionary alloc] initWithCapacity:32];
216 static NSMutableDictionary *PathImages_ = [[NSMutableDictionary alloc] initWithCapacity:16];
217 static NSMutableDictionary *Cache_ = [[NSMutableDictionary alloc] initWithCapacity:64];
218 static NSMutableDictionary *Strings_ = [[NSMutableDictionary alloc] initWithCapacity:0];
219 static NSMutableDictionary *Bundles_ = [[NSMutableDictionary alloc] initWithCapacity:2];
221 static NSFileManager *Manager_;
222 static NSMutableArray *Themes_;
224 static NSDictionary *English_;
225 static NSMutableDictionary *Info_;
228 static NSMutableDictionary *Themed_ = [[NSMutableDictionary alloc] initWithCapacity:128];
230 static unsigned Scale_ = 0;
232 static unsigned $getScale$(NSString *path) {
233 NSString *name(path);
235 #define StripName(strip) \
236 if ([name hasSuffix:@ strip]) \
237 name = [name substringWithRange:NSMakeRange(0, [name length] - sizeof(strip) - 1)];
241 StripName("~iphone");
244 return [name hasSuffix:@"@2x"] ? 2 : 1;
247 static NSArray *$useScale$(NSArray *files, bool use = true) {
248 if (use && Scale_ == 0) {
249 UIScreen *screen([UIScreen mainScreen]);
250 if ([screen respondsToSelector:@selector(scale)])
251 Scale_ = [screen scale];
259 NSString *idiom(IsWild_ ? @"ipad" : @"iphone");
261 NSMutableArray *scaled([NSMutableArray arrayWithCapacity:([files count] * 4)]);
263 for (NSString *file in files) {
264 NSString *base([file stringByDeletingPathExtension]);
265 NSString *extension([file pathExtension]);
269 [scaled addObject:[NSString stringWithFormat:@"%@@2x~%@.%@", base, idiom, extension]];
271 [scaled addObject:[NSString stringWithFormat:@"%@@2x.%@", base, extension]];
274 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
276 // if (!IsWild_) <- support old themes
277 [scaled addObject:file];
278 } else if ([base hasSuffix: @"@2x"]) {
279 [scaled addObject:[NSString stringWithFormat:@"%@~iphone.%@", base, extension]];
280 [scaled addObject:file];
282 // XXX: this actually can't be used, as the person loading the file doesn't realize that the @2x changed
283 /*NSString *rest([base substringWithRange:NSMakeRange(0, [base length] - 3)]);
284 [scaled addObject:[NSString stringWithFormat:@"%@~iphone.%@", rest, extension]];
285 [scaled addObject:[rest stringByAppendingPathExtension:extension]];*/
287 // XXX: this code isn't really complete
289 [scaled addObject:file];
291 if ([base hasSuffix:@"~iphone"])
292 [scaled addObject:[[base substringWithRange:NSMakeRange(0, [base length] - 7)] stringByAppendingPathExtension:extension]];
299 static NSString *$getTheme$(NSArray *files, NSArray *themes = Themes_) {
300 // XXX: this is not reasonable; OMG
303 @synchronized (Themed_) {
304 if (NSString *path = [Themed_ objectForKey:key])
305 return reinterpret_cast<id>(path) == [NSNull null] ? nil : path;
309 NSLog(@"WB:Debug: %@", [files description]);
313 for (NSString *theme in Themes_)
314 for (NSString *file in files) {
315 path = [NSString stringWithFormat:@"%@/%@", theme, file];
316 if ([Manager_ fileExistsAtPath:path])
323 @synchronized (Themed_) {
324 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:key];
330 // $pathForFile$inBundle$() {{{
331 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool ui) {
332 NSString *identifier = [bundle bundleIdentifier];
333 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
335 if (identifier != nil)
336 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
337 if (NSString *folder = [[bundle bundlePath] lastPathComponent]) {
338 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
339 NSString *base([folder stringByDeletingPathExtension]);
340 if ([base hasSuffix:@"~iphone"])
341 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 7)], [folder pathExtension], file]];
344 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
346 #define remapResourceName(oldname, newname) \
347 else if ([file isEqualToString:(oldname)]) \
348 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
350 bool summer(SpringBoard_ && SummerBoard_);
352 if (identifier == nil);
353 else if ([identifier isEqualToString:@"com.apple.chatkit"])
354 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
355 else if ([identifier isEqualToString:@"com.apple.calculator"])
356 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
358 remapResourceName(@"FSO_BG.png", @"StatusBar")
359 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
360 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
362 [names addObject:[NSString stringWithFormat:@"Fallback/%@", file]];
364 if (NSString *path = $getTheme$($useScale$(names, ui)))
371 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
372 NSString *identifier = [self bundleIdentifier];
373 NSString *path = [self path];
374 NSString *folder = [path lastPathComponent];
375 NSString *dname = [self displayName];
376 NSString *didentifier = [self displayIdentifier];
379 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
381 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
383 /* XXX: I might need to keep this for backwards compatibility
384 if (identifier != nil)
385 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
387 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
389 #define testForIcon(Name) \
390 if (NSString *name = Name) \
391 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
393 if (![didentifier isEqualToString:identifier])
394 testForIcon(didentifier);
396 testForIcon(identifier);
399 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
402 if (didentifier != nil) {
403 testForIcon([English_ objectForKey:didentifier]);
405 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
406 if ([parts count] != 1)
407 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
408 testForIcon([english objectForKey:[parts lastObject]]);
411 if (NSString *path = $getTheme$(names))
417 // -[NSBundle wb$bundleWithFile] {{{
418 @interface NSBundle (WinterBoard)
419 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
422 @implementation NSBundle (WinterBoard)
424 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
425 path = [path stringByDeletingLastPathComponent];
426 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
429 NSBundle *bundle([Bundles_ objectForKey:path]);
430 if (reinterpret_cast<id>(bundle) == [NSNull null])
432 else if (bundle == nil) {
433 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
434 bundle = [NSBundle bundleWithPath:path];
436 bundle = [NSBundle wb$bundleWithFile:path];
438 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
439 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
447 // -[NSString wb$themedPath] {{{
448 @interface NSString (WinterBoard)
449 - (NSString *) wb$themedPath;
452 @implementation NSString (WinterBoard)
454 - (NSString *) wb$themedPath {
455 if ([self hasPrefix:@"/Library/Themes/"])
459 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
461 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
462 NSString *file([self stringByResolvingSymlinksInPath]);
463 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
464 if ([file hasPrefix:prefix]) {
465 NSUInteger length([prefix length]);
466 if (length != [file length])
467 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
478 void WBLogRect(const char *tag, struct CGRect rect) {
479 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
482 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
483 CGRect frame([view frame]);
484 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]);
486 for (UIView *child in [view subviews])
487 WBLogHierarchy(child, index++, indent + 1);
490 UIImage *$cacheForImage$(UIImage *image) {
491 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
492 CGRect rect = {CGPointMake(1, 1), [image size]};
493 CGSize size = {rect.size.width + 2, rect.size.height + 2};
495 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
496 CGColorSpaceRelease(space);
498 CGContextDrawImage(context, rect, [image CGImage]);
499 CGImageRef ref(CGBitmapContextCreateImage(context));
500 CGContextRelease(context);
502 UIImage *cache([UIImage imageWithCGImage:ref]);
508 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
509 //if ([name isEqualToString:@"icons"]) return nil;
510 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
513 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
514 NSString *key([icon displayIdentifier]);
516 if (UIImage *image = [icon icon]) {
517 CGSize size = [image size];
518 if (size.width != 59 || size.height != 60) {
519 UIImage *cache($cacheForImage$(image));
520 [Cache_ setObject:cache forKey:key];
525 _SBIconModel$cacheImageForIcon$(self, sel, icon);
528 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
529 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
530 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
532 NSString *key([icon displayIdentifier]);
534 if (UIImage *image = [icon icon]) {
535 CGSize size = [image size];
536 if (size.width != 59 || size.height != 60) {
537 UIImage *cache($cacheForImage$(image));
538 [Cache_ setObject:cache forKey:key];
544 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
545 NSString *key([icon displayIdentifier]);
546 if (UIImage *image = [Cache_ objectForKey:key])
549 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
552 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
554 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
555 NSString *key([icon displayIdentifier]);
556 if (UIImage *image = [Cache_ objectForKey:key])
559 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
562 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
563 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
564 [self setBackgroundColor:[UIColor clearColor]];
565 for (UIView *child in [self subviews])
566 [child setBackgroundColor:[UIColor clearColor]];
570 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
571 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
572 [self setBackgroundColor:[UIColor clearColor]];
576 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
577 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
578 float inset([self edgeInset]);
579 [[UIColor clearColor] set];
580 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
581 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
584 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
585 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
586 if (NSString *path = $pathForIcon$([self application]))
587 return [UIImage imageWithContentsOfFile:path];
588 return _SBApplicationIcon$icon(self, sel);
591 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
593 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
594 if (IsWild_ && false) // XXX: delete this code, it should not be supported
595 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
596 return [UIImage imageWithContentsOfFile:path72];
597 if (NSString *path = $pathForIcon$([self application]))
598 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
600 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
601 width = [$SBIcon defaultIconImageSize].width;
604 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
607 return _SBApplicationIcon$generateIconImage$(self, sel, type);
610 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
612 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
613 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
614 return [UIImage imageWithContentsOfFile:path];
615 return _SBWidgetApplicationIcon$icon(self, sel);
618 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
620 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
621 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
622 return [UIImage imageWithContentsOfFile:path];
623 return _SBBookmarkIcon$icon(self, sel);
626 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
627 if (NSString *path = $pathForIcon$(self))
629 return _SBApplication$pathForIcon(self, sel);
632 static UIImage *CachedImageAtPath(NSString *path) {
633 path = [path stringByResolvingSymlinksInPath];
634 UIImage *image = [PathImages_ objectForKey:path];
636 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
637 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
639 image = [image autorelease];
640 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
644 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
645 NSBundle *bundle = [NSBundle mainBundle];
647 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
648 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
649 return CachedImageAtPath(path);
650 return __UIApplicationImageWithName(name);
653 #define WBDelegate(delegate) \
654 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
656 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
657 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
659 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
663 - (void) forwardInvocation:(NSInvocation*)inv { \
664 SEL sel = [inv selector]; \
665 if ([delegate respondsToSelector:sel]) \
666 [inv invokeWithTarget:delegate]; \
668 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
671 // %hook -[NSBundle pathForResource:ofType:] {{{
672 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
673 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
675 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
676 if (NSString *path = $pathForFile$inBundle$(file, self, false))
678 return MSOldCall(resource, type);
682 static void $drawLabel$(NSString *label, CGRect rect, NSString *style, NSString *custom) {
683 bool ellipsis(false);
684 float max = rect.size.width - 11, width;
686 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
689 size_t length([label length]);
690 float spacing((width - max) / (length - 1));
692 if (spacing > 1.25) {
694 label = [label substringToIndex:(length - 1)];
698 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
702 label = [label stringByAppendingString:@"..."];
705 style = [style stringByAppendingString:custom];
707 CGSize size = [label sizeWithStyle:style forWidth:rect.size.width];
708 [label drawAtPoint:CGPointMake((rect.size.width - size.width) / 2 + rect.origin.x, rect.origin.y) withStyle:style];
711 static struct WBStringDrawingState {
712 WBStringDrawingState *next_;
716 } *stringDrawingState_;
718 extern "C" CGColorSpaceRef CGContextGetFillColorSpace(CGContextRef);
719 extern "C" void CGContextGetFillColor(CGContextRef, CGFloat[]);
721 static NSString *WBColorMarkup() {
722 CGContextRef context(UIGraphicsGetCurrentContext());
723 //NSLog(@"XXX:1:%p", context);
727 CGColorSpaceRef space(CGContextGetFillColorSpace(context));
728 //NSLog(@"XXX:2:%p", space);
732 size_t number(CGColorSpaceGetNumberOfComponents(space));
733 //NSLog(@"XXX:3:%u", number);
737 CGFloat components[number + 1];
738 CGContextGetFillColor(context, components);
761 return [NSString stringWithFormat:@"color: rgba(%g, %g, %g, %g)", r * 255, g * 255, b * 255, a];
764 MSInstanceMessageHook6(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode,letterSpacing,includeEmoji, CGPoint, point, float, width, UIFont *, font, UILineBreakMode, mode, float, spacing, BOOL, emoji) {
765 //NSLog(@"XXX: @\"%@\" %g", self, spacing);
767 WBStringDrawingState *state(stringDrawingState_);
769 return MSOldCall(point, width, font, mode, spacing, emoji);
771 if (--state->count_ == 0)
772 stringDrawingState_ = state->next_;
773 if (state->info_ == nil)
774 return MSOldCall(point, width, font, mode, spacing, emoji);
776 NSString *info([Info_ objectForKey:state->info_]);
778 return MSOldCall(point, width, font, mode, spacing, emoji);
780 NSString *base(state->base_ ?: @"");
781 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
782 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
786 extern "C" NSString *NSStringFromCGRect(CGRect rect);
788 MSInstanceMessageHook7(CGSize, NSString, _drawInRect,withFont,lineBreakMode,alignment,lineSpacing,includeEmoji,truncationRect, CGRect, rect, UIFont *, font, UILineBreakMode, mode, UITextAlignment, alignment, float, spacing, BOOL, emoji, CGRect, truncation) {
789 //NSLog(@"XXX: &\"%@\" %@ \"%@\" %u %u %g %u %@", self, NSStringFromCGRect(rect), font, mode, alignment, spacing, emoji, NSStringFromCGRect(truncation));
791 WBStringDrawingState *state(stringDrawingState_);
793 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
795 if (--state->count_ == 0)
796 stringDrawingState_ = state->next_;
797 if (state->info_ == nil)
798 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
800 NSString *info([Info_ objectForKey:state->info_]);
802 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
807 case UITextAlignmentLeft:
810 case UITextAlignmentCenter:
811 textAlign = @"center";
813 case UITextAlignmentRight:
814 textAlign = @"right";
818 NSString *base(state->base_ ?: @"");
819 NSString *extra([NSString stringWithFormat:@"text-align: %@", textAlign]);
822 $drawLabel$(self, rect, [NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], WBColorMarkup(), base], info);
824 [self drawInRect:rect withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
829 MSInstanceMessageHook4(CGSize, NSString, sizeWithFont,forWidth,lineBreakMode,letterSpacing, UIFont *, font, float, width, UILineBreakMode, mode, float, spacing) {
830 //NSLog(@"XXX: #\"%@\" \"%@\" %g %u %g", self, font, width, mode, spacing);
832 WBStringDrawingState *state(stringDrawingState_);
834 return MSOldCall(font, width, mode, spacing);
836 if (--state->count_ == 0)
837 stringDrawingState_ = state->next_;
838 if (state->info_ == nil)
839 return MSOldCall(font, width, mode, spacing);
841 NSString *info([Info_ objectForKey:state->info_]);
843 return MSOldCall(font, width, mode, spacing);
845 NSString *base(state->base_ ?: @"");
846 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
847 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info] forWidth:width];
850 MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) {
851 //NSLog(@"XXX: ?\"%@\"", self);
853 WBStringDrawingState *state(stringDrawingState_);
855 return MSOldCall(font);
857 if (--state->count_ == 0)
858 stringDrawingState_ = state->next_;
859 if (state->info_ == nil)
860 return MSOldCall(font);
862 NSString *info([Info_ objectForKey:state->info_]);
864 return MSOldCall(font);
866 NSString *base(state->base_ ?: @"");
867 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), base, info] forWidth:65535];
870 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
871 WBStringDrawingState badgeState = {NULL, 1, @""
874 stringDrawingState_ = &badgeState;
876 UIImage *image(MSOldCall(text));
878 stringDrawingState_ = NULL;
882 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
883 WBStringDrawingState dayState = {NULL, 2, @""
884 // XXX: this is only correct on an iPod dock
885 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
886 , @"CalendarIconDayStyle"};
888 WBStringDrawingState sizeState = {&dayState, 7, nil, nil};
890 WBStringDrawingState dateState = {&sizeState, 2, @""
891 , @"CalendarIconDateStyle"};
893 stringDrawingState_ = &dateState;
895 UIImage *image(MSOldCall(type));
897 stringDrawingState_ = NULL;
901 MSInstanceMessageHook1(UIImage *, UIStatusBarTimeItemView, contentsImageForStyle, int, style) {
902 WBStringDrawingState timeState = {NULL, 0, @""
905 stringDrawingState_ = &timeState;
907 UIImage *image(MSOldCall(style));
909 stringDrawingState_ = NULL;
913 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
914 NSBundle *bundle([NSBundle mainBundle]);
916 CFLocaleRef locale(CFLocaleCopyCurrent());
917 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
920 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
922 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
923 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
924 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
925 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
929 CFRelease(formatter);
931 NSString *datestyle([@""
932 "font-family: Helvetica; "
933 "font-weight: bold; "
936 "" stringByAppendingString:(IsWild_
937 ? @"font-size: 54px; "
938 : @"font-size: 39px; "
941 NSString *daystyle([@""
942 "font-family: Helvetica; "
943 "font-weight: bold; "
945 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
946 "" stringByAppendingString:(IsWild_
947 ? @"font-size: 11px; "
948 : @"font-size: 9px; "
951 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
952 datestyle = [datestyle stringByAppendingString:style];
953 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
954 daystyle = [daystyle stringByAppendingString:style];
956 float width([self bounds].size.width);
958 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
959 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
961 unsigned base0(IsWild_ ? 89 : 70);
962 if ($GSFontGetUseLegacyFontMetrics())
964 unsigned base1(IsWild_ ? 18 : 16);
971 [(NSString *)date drawAtPoint:CGPointMake(
972 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
973 ) withStyle:datestyle];
975 [(NSString *)day drawAtPoint:CGPointMake(
976 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
977 ) withStyle:daystyle];
983 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
984 void $setBarStyle$_(NSString *name, int &style) {
986 NSLog(@"WB:Debug:%@Style:%d", name, style);
987 NSNumber *number = nil;
989 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
991 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
993 style = [number intValue];
995 NSLog(@"WB:Debug:%@Style=%d", name, style);
999 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
1000 $setBarStyle$_(@"Toolbar", style);
1001 return MSOldCall(style);
1004 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
1005 $setBarStyle$_(@"NavigationBar", style);
1006 return MSOldCall(style);
1010 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
1011 [[self superview] setBackgroundColor:[UIColor clearColor]];
1012 _SBButtonBar$didMoveToSuperview(self, sel);
1015 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
1016 [[self superview] setBackgroundColor:[UIColor clearColor]];
1017 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
1020 static NSArray *Wallpapers_;
1021 static bool Papered_;
1022 static bool Docked_;
1023 static bool SMSBackgrounded_;
1024 static NSString *WallpaperFile_;
1025 static UIImageView *WallpaperImage_;
1026 static UIWebDocumentView *WallpaperPage_;
1027 static NSURL *WallpaperURL_;
1029 #define _release(object) \
1030 do if (object != nil) { \
1035 static UIImage *$getImage$(NSString *path) {
1036 UIImage *image([UIImage imageWithContentsOfFile:path]);
1038 unsigned scale($getScale$(path));
1039 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
1040 [image setScale:scale];
1045 static UIImage *$getDefaultDesktopImage$() {
1046 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
1047 return $getImage$(path);
1051 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
1052 return $getDefaultDesktopImage$() ?: MSOldCall();
1055 MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
1056 return $getDefaultDesktopImage$() ?: MSOldCall();
1059 MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
1060 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
1061 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
1062 if (UIImage *image = $getDefaultDesktopImage$()) {
1063 [self setImage:image];
1073 // %hook -[SBUIController init] {{{
1074 MSInstanceMessageHook0(id, SBUIController, init) {
1079 NSString *paper($getTheme$(Wallpapers_));
1081 paper = [paper stringByDeletingLastPathComponent];
1085 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
1086 char *machine = new char[size];
1088 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
1089 perror("sysctlbyname(\"hw.machine\", ?)");
1094 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
1098 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
1101 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
1102 if (&_wallpaperView != NULL) {
1103 [_wallpaperView removeFromSuperview];
1104 [_wallpaperView release];
1105 _wallpaperView = nil;
1109 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
1110 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
1113 if (&_contentLayer != NULL)
1114 player = &_contentLayer;
1115 else if (&_contentView != NULL)
1116 player = &_contentView;
1119 UIView *layer(player == NULL ? nil : *player);
1121 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
1122 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
1123 [window setContentView:content];
1125 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
1126 [window setBackgroundColor:[_window backgroundColor]];
1127 [_window setBackgroundColor:[UIColor clearColor]];
1129 [window setLevel:-1000];
1130 [window setHidden:NO];
1132 /*if (player != NULL)
1133 *player = content;*/
1135 [content setBackgroundColor:[layer backgroundColor]];
1136 [layer setBackgroundColor:[UIColor clearColor]];
1139 if (!SummerBoard_ || !IsWild_)
1142 CGRect bounds([content bounds]);
1143 bounds.origin.y = -30;
1144 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
1145 [content addSubview:indirect];
1146 [indirect zoomToScale:2.4];
1149 _release(WallpaperFile_);
1150 _release(WallpaperImage_);
1151 _release(WallpaperPage_);
1152 _release(WallpaperURL_);
1155 NSArray *themes([NSArray arrayWithObject:paper]);
1157 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1161 static AVController *controller_(nil);
1162 if (controller_ == nil) {
1163 AVQueue *queue([AVQueue avQueue]);
1164 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1167 AVQueue *queue([controller_ queue]);
1169 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1170 [controller_ setLayer:[video _layer]];
1172 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1173 [queue appendItem:item error:&error];
1175 [controller_ play:&error];
1176 #elif UseMPMoviePlayerController
1177 NSURL *url([NSURL fileURLWithPath:path]);
1178 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1179 controller.movieControlMode = MPMovieControlModeHidden;
1182 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1183 [video setMovieWithPath:path];
1184 [video setRepeatMode:1];
1185 [video setRepeatGap:-1];
1186 [video playFromBeginning];;
1189 [indirect addSubview:video];
1192 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1193 if (UIImage *image = $getImage$(path)) {
1194 WallpaperFile_ = [path retain];
1195 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1196 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1197 [WallpaperImage_ setAlpha:[number floatValue]];
1198 [indirect addSubview:WallpaperImage_];
1202 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1203 CGRect bounds = [indirect bounds];
1205 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1206 [view setAutoresizes:true];
1208 WallpaperPage_ = [view retain];
1209 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1211 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1213 [view setBackgroundColor:[UIColor clearColor]];
1214 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1215 [view setDrawsBackground:NO];
1216 [[view webView] setDrawsBackground:NO];
1218 [indirect addSubview:view];
1222 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1223 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1224 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1225 if ([Manager_ fileExistsAtPath:html]) {
1226 CGRect bounds = [indirect bounds];
1228 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1229 [view setAutoresizes:true];
1231 NSURL *url = [NSURL fileURLWithPath:html];
1232 [view loadRequest:[NSURLRequest requestWithURL:url]];
1234 [view setBackgroundColor:[UIColor clearColor]];
1235 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1236 [view setDrawsBackground:NO];
1237 [[view webView] setDrawsBackground:NO];
1239 [indirect addSubview:view];
1247 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1248 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1249 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1251 if (path != nil && _backgroundView != nil)
1254 _SBAwayView$updateDesktopImage$(self, sel, image);
1257 CGRect bounds = [self bounds];
1259 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1260 [view setAutoresizes:true];
1262 if (WallpaperPage_ != nil)
1263 [WallpaperPage_ release];
1264 WallpaperPage_ = [view retain];
1266 if (WallpaperURL_ != nil)
1267 [WallpaperURL_ release];
1268 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1270 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1272 [[view webView] setDrawsBackground:false];
1273 [view setBackgroundColor:[UIColor clearColor]];
1275 [self insertSubview:view aboveSubview:_backgroundView];
1279 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1280 extern "C" CGColorRef CGGStateGetFillColor(void *);
1281 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1282 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1284 /* WBTimeLabel {{{ */
1285 @interface WBTimeLabel : NSProxy {
1287 _transient SBStatusBarTimeView *view_;
1290 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1294 @implementation WBTimeLabel
1301 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1302 time_ = [time retain];
1307 - (NSString *) description {
1313 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1314 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1315 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1317 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1318 "font-family: Helvetica; "
1319 "font-weight: bold; "
1322 "%@", _mode ? @"white" : @"black", custom]];
1327 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1332 /* WBBadgeLabel {{{ */
1333 @interface WBBadgeLabel : NSProxy {
1337 - (id) initWithBadge:(NSString *)badge;
1338 - (NSString *) description;
1342 @implementation WBBadgeLabel
1349 - (id) initWithBadge:(NSString *)badge {
1350 badge_ = [badge retain];
1354 - (NSString *) description {
1355 return [badge_ description];
1360 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1361 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1362 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1363 "font-family: Helvetica; "
1364 "font-weight: bold; "
1372 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1379 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1380 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1381 alpha = [number floatValue];
1382 return MSOldCall(alpha);
1385 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1386 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1387 alpha = [number floatValue];
1388 return MSOldCall(alpha);
1391 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1392 if ((self = MSOldCall()) != nil) {
1393 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1394 // XXX: note: this is overridden above, which is silly
1395 float alpha([number floatValue]);
1396 if ([self respondsToSelector:@selector(setIconImageAlpha:)])
1397 [self setIconImageAlpha:alpha];
1398 if ([self respondsToSelector:@selector(setIconLabelAlpha:)])
1399 [self setIconLabelAlpha:alpha];
1400 if ([self respondsToSelector:@selector(setAlpha:)])
1401 [self setAlpha:alpha];
1406 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1407 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1408 alpha = [number floatValue];
1409 return MSOldCall(alpha);
1413 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1414 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1415 id &_badge(MSHookIvar<id>(self, "_badge"));
1417 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1422 void SBStatusBarController$setStatusBarMode(int &mode) {
1424 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1425 if (mode < 100) // 104:hidden 105:glowing
1426 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1427 mode = [number intValue];
1430 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1431 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1432 SBStatusBarController$setStatusBarMode(mode);
1433 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1436 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1437 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1438 SBStatusBarController$setStatusBarMode(mode);
1439 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1442 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) {
1443 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1444 SBStatusBarController$setStatusBarMode(mode);
1445 //NSLog(@"mode=%u", mode);
1446 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1449 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1450 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1451 mode = [number intValue];
1452 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1455 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1456 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1458 NSLog(@"operatorNameStyle= %@", style);
1459 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1460 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1464 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1466 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1467 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1470 // XXX: replace this with [SBStatusBarTimeView tile]
1471 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1472 id &_time(MSHookIvar<id>(self, "_time"));
1473 if (_time != nil && [_time class] != [WBTimeLabel class])
1474 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1475 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1478 @interface UIView (WinterBoard)
1479 - (bool) wb$isWBImageView;
1480 - (void) wb$logHierarchy;
1481 - (void) wb$setBackgroundColor:(UIColor *)color;
1484 @implementation UIView (WinterBoard)
1486 - (bool) wb$isWBImageView {
1490 - (void) wb$logHierarchy {
1491 WBLogHierarchy(self);
1494 - (void) wb$setBackgroundColor:(UIColor *)color {
1495 [self setBackgroundColor:color];
1496 for (UIView *child in [self subviews])
1497 [child wb$setBackgroundColor:color];
1502 @interface WBImageView : UIImageView {
1505 - (bool) wb$isWBImageView;
1506 - (void) wb$updateFrame;
1509 @implementation WBImageView
1511 - (bool) wb$isWBImageView {
1515 - (void) wb$updateFrame {
1516 CGRect frame([self frame]);
1519 for (UIView *view(self); ; ) {
1520 view = [view superview];
1523 frame.origin.y -= [view frame].origin.y;
1526 [self setFrame:frame];
1531 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1532 NSArray *subviews([self subviews]);
1533 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1534 if (view != nil && [view wb$isWBImageView])
1535 [view wb$updateFrame];
1536 _SBIconList$setFrame$(self, sel, frame);
1539 static void $addPerPageView$(unsigned i, UIView *list) {
1540 NSString *path($getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]]));
1544 NSArray *subviews([list subviews]);
1546 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1547 if (view == nil || ![view wb$isWBImageView]) {
1548 view = [[[WBImageView alloc] init] autorelease];
1549 [list insertSubview:view atIndex:0];
1552 UIImage *image([UIImage imageWithContentsOfFile:path]);
1554 CGRect frame([view frame]);
1555 frame.size = [image size];
1556 [view setFrame:frame];
1558 [view setImage:image];
1559 [view wb$updateFrame];
1562 static void $addPerPageViews$(NSArray *lists) {
1563 for (unsigned i(0), e([lists count]); i != e; ++i)
1564 $addPerPageView$(i, [lists objectAtIndex:i]);
1567 MSInstanceMessageHook0(void, SBIconController, updateNumberOfRootIconLists) {
1568 NSArray *&_rootIconLists(MSHookIvar<NSArray *>(self, "_rootIconLists"));
1569 $addPerPageViews$(_rootIconLists);
1573 MSInstanceMessageHook0(void, SBIconContentView, layoutSubviews) {
1576 if (SBIconController *controller = [$SBIconController sharedInstance]) {
1577 UIView *&_dockContainerView(MSHookIvar<UIView *>(controller, "_dockContainerView"));
1578 if (&_dockContainerView != NULL)
1579 [[_dockContainerView superview] bringSubviewToFront:_dockContainerView];
1583 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1584 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1585 $addPerPageViews$([_iconModel iconLists]);
1586 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1589 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1590 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1592 [self setClipsToBounds:NO];
1596 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1597 static bool gssc(false);
1599 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1600 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1603 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1604 [Info_ setObject:[NSNumber numberWithBool:(
1606 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1607 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1608 )] forKey:@"UndockedIconLabels"];
1611 id &_label(MSHookIvar<id>(self, "_label"));
1612 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1615 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1616 [_label setInDock:docked];
1618 _SBIconLabel$setInDock$(self, sel, docked);
1619 [self setNeedsDisplay];
1622 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1623 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1626 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1627 _SBDockIconListView$setFrame$(self, sel, frame);
1630 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1631 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1632 NSString *identifier = [self bundleIdentifier];
1633 NSLocale *locale = [NSLocale currentLocale];
1634 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1636 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1637 NSString *file = table == nil ? @"Localizable" : table;
1638 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1639 NSDictionary *strings;
1640 if ((strings = [Strings_ objectForKey:name]) != nil) {
1641 if (static_cast<id>(strings) != [NSNull null]) strings:
1642 if (NSString *value = [strings objectForKey:key])
1644 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1647 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1648 [Strings_ setObject:[strings autorelease] forKey:name];
1652 [Strings_ setObject:[NSNull null] forKey:name];
1653 return MSOldCall(key, value, table);
1656 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1657 MSClassHook(WebCoreFrameBridge)
1659 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1662 void **core(reinterpret_cast<void **>([node _node]));
1663 if (core == NULL || core[6] == NULL)
1665 return MSOldCall(node, width);
1669 MSInstanceMessage1(void, SBIconLabel, drawRect, CGRect, rect) {
1670 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1673 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1674 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1676 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1678 NSString *style = [NSString stringWithFormat:@""
1679 "font-family: Helvetica; "
1680 "font-weight: bold; "
1682 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1683 ? @"font-size: 12px; "
1684 : @"font-size: 11px; "
1688 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1690 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1692 NSString *custom([Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")]);
1694 $drawLabel$(label, [self bounds], style, custom);
1697 MSInstanceMessage0(CGImageRef, SBIconLabel, buildLabelImage) {
1698 bool docked((MSHookIvar<unsigned>(self, "_inDock") & 0x2) != 0);
1700 WBStringDrawingState labelState = {NULL, 0, @""
1701 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1703 stringDrawingState_ = &labelState;
1706 CGImageRef image(MSOldCall());
1709 stringDrawingState_ = NULL;
1714 MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1715 if ((self = MSOldCall(frame, delegate)) != nil) {
1716 [self setBackgroundColor:[UIColor clearColor]];
1720 MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1721 return SMSBackgrounded_ ? NO : MSOldCall();
1724 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1725 [self wb$setBackgroundColor:[UIColor clearColor]];
1729 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1731 [balloon setBackgroundColor:[UIColor clearColor]];
1734 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1735 MSOldCall([UIColor clearColor]);
1736 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1740 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1741 if ((self = MSOldCall(style, reuse)) != nil) {
1742 [self setBackgroundColor:[UIColor clearColor]];
1743 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1748 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1749 if ((self = MSOldCall(style, reuse)) != nil) {
1750 [self setBackgroundColor:[UIColor clearColor]];
1751 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1755 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1756 if ((self = MSOldCall(style, reuse)) != nil) {
1757 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1758 [_label setBackgroundColor:[UIColor clearColor]];
1762 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1763 MSOldCall(UITableViewCellSeparatorStyleNone);
1766 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1767 if ((self = MSOldCall(frame, style)) != nil) {
1768 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1772 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1775 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1776 if (UIImage *image = $getImage$(path)) {
1777 SMSBackgrounded_ = true;
1779 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1780 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1782 if (&_transcriptTable != NULL)
1783 table = _transcriptTable;
1784 else if (&_transcriptLayer != NULL)
1785 table = _transcriptLayer;
1789 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1790 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1793 [placard insertSubview:background atIndex:0];
1795 [table setBackgroundColor:[UIColor clearColor]];
1796 [placard insertSubview:background belowSubview:table];
1802 // %hook _UIImageWithName() {{{
1803 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1805 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1812 if (_UIPackedImageTableGetIdentifierForName != NULL)
1813 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1814 else if (_UISharedImageNameGetIdentifier != NULL) {
1815 identifier = _UISharedImageNameGetIdentifier(name);
1816 packed = identifier != -1;
1823 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1826 return __UIImageWithName(name);
1828 NSNumber *key([NSNumber numberWithInt:identifier]);
1829 UIImage *image([UIImages_ objectForKey:key]);
1831 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1832 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1833 image = $getImage$(path);
1834 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1838 image = __UIImageWithName(name);
1841 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1842 if (![Manager_ fileExistsAtPath:path])
1843 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1850 // %hook _UIImageWithNameInDomain() {{{
1851 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1852 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1853 UIImage *image([PathImages_ objectForKey:key]);
1855 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1857 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1858 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1859 image = $getImage$(path);
1860 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1861 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1865 // %hook GSFontCreateWithName() {{{
1866 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1868 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1869 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1870 name = [font UTF8String];
1871 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1872 // size *= [scale floatValue];
1873 return _GSFontCreateWithName(name, traits, size);
1877 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1878 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1880 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1882 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1884 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1885 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1887 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1890 NSString *path = [NSString stringWithUTF8String:a1];
1891 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1892 NSString *file = [path substringFromIndex:31];
1893 for (NSString *theme in Themes_) {
1894 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1895 if ([Manager_ fileExistsAtPath:path]) {
1896 strcpy(a1, [path UTF8String]);
1905 static void ChangeWallpaper(
1906 CFNotificationCenterRef center,
1910 CFDictionaryRef info
1913 NSLog(@"WB:Debug:ChangeWallpaper!");
1916 if (WallpaperFile_ != nil) {
1917 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1919 image = [image autorelease];
1922 if (WallpaperImage_ != nil)
1923 [WallpaperImage_ setImage:image];
1924 if (WallpaperPage_ != nil)
1925 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1929 #define WBRename(name, sel, imp) \
1930 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
1932 template <typename Type_>
1933 static void msset(Type_ &function, MSImageRef image, const char *name) {
1934 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1937 template <typename Type_>
1938 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1939 struct nlist &name(nl[index]);
1940 uintptr_t value(name.n_value);
1941 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1942 value |= 0x00000001;
1943 function = reinterpret_cast<Type_>(value);
1946 template <typename Type_>
1947 static void dlset(Type_ &function, const char *name) {
1948 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1951 // %hook CGImageReadCreateWithFile() {{{
1952 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1954 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1955 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1956 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1962 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
1963 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1964 if (style == nil || [style length] == 0)
1965 style = @"font-family: Helvetica; font-size: 12px";
1966 //NSLog(@"XXX:draw(%@)", [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
1967 return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
1970 static void NSString$drawInRect$withStyle$(NSString *self, SEL _cmd, CGRect rect, NSString *style) {
1971 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1972 if (style == nil || [style length] == 0)
1973 style = @"font-family: Helvetica; font-size: 12px";
1974 return [[WBMarkup sharedMarkup] drawString:self inRect:rect withStyle:style];
1977 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
1978 if (style == nil || [style length] == 0)
1979 style = @"font-family: Helvetica; font-size: 12px";
1980 //NSLog(@"XXX:size(%@)", [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
1981 return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width];
1984 static void SBInitialize() {
1986 WBRename(SBApplication, pathForIcon, pathForIcon);
1987 WBRename(SBApplicationIcon, icon, icon);
1988 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1991 WBRename(SBBookmarkIcon, icon, icon);
1992 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1993 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1994 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1995 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
1997 WBRename(SBWidgetApplicationIcon, icon, icon);
1999 WBRename(SBDockIconListView, setFrame:, setFrame$);
2000 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
2002 if (kCFCoreFoundationVersionNumber < 600 || SummerBoard_)
2003 WBRename(SBIconLabel, drawRect:, drawRect$);
2005 WBRename(SBIconLabel, buildLabelImage, buildLabelImage);
2007 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
2008 WBRename(SBIconLabel, setInDock:, setInDock$);
2010 WBRename(SBIconList, setFrame:, setFrame$);
2012 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
2013 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
2014 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
2015 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
2017 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
2018 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
2019 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
2021 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
2023 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
2024 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
2025 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
2026 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
2027 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
2028 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
2029 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
2030 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
2031 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
2034 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
2038 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2040 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
2041 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
2043 Manager_ = [[NSFileManager defaultManager] retain];
2044 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
2046 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
2048 // Load Settings.plist {{{
2049 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
2050 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
2051 SummerBoard_ = [value boolValue];
2053 SummerBoard_ = true;
2055 if (NSNumber *value = [settings objectForKey:@"Debug"])
2056 Debug_ = [value boolValue];
2057 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
2058 UIDebug_ = [value boolValue];
2060 NSArray *themes([settings objectForKey:@"Themes"]);
2062 if (NSString *theme = [settings objectForKey:@"Theme"])
2063 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
2065 [NSNumber numberWithBool:true], @"Active",
2069 for (NSDictionary *theme in themes) {
2070 NSNumber *active([theme objectForKey:@"Active"]);
2071 if (![active boolValue])
2074 NSString *name([theme objectForKey:@"Name"]);
2078 NSString *theme(nil);
2080 #define testForTheme(format...) \
2081 if (theme == nil) { \
2082 NSString *path = [NSString stringWithFormat:format]; \
2083 if ([Manager_ fileExistsAtPath:path]) { \
2084 [Themes_ addObject:path]; \
2089 testForTheme(@"/Library/Themes/%@.theme", name)
2090 testForTheme(@"/Library/Themes/%@", name)
2091 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
2096 // Merge Info.plist {{{
2097 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2099 for (NSString *theme in Themes_)
2100 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
2101 for (NSString *key in [info allKeys])
2102 if ([Info_ objectForKey:key] == nil)
2103 [Info_ setObject:[info objectForKey:key] forKey:key];
2107 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
2108 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
2109 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
2112 // GraphicsServices {{{
2114 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
2118 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
2119 void *(*CGImageReadCreateWithFile)(NSString *, int);
2120 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
2121 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
2126 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
2127 Papered_ = $getTheme$(Wallpapers_) != nil;
2128 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
2130 CFNotificationCenterAddObserver(
2131 CFNotificationCenterGetDarwinNotifyCenter(),
2132 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
2135 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
2136 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
2137 if (MediaPlayer != nil)
2140 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
2141 $MPVideoView = objc_getClass("MPVideoView");
2148 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
2149 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
2150 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v28@0:4{CGRect={CGSize=ff}{CGSize=ff}}8@24");
2151 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
2154 memset(nl, 0, sizeof(nl));
2155 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
2156 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
2157 nl[2].n_un.n_name = (char *) "__UIKitBundle";
2158 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
2159 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
2162 nlset(_UIApplicationImageWithName, nl, 0);
2163 nlset(_UIImageWithNameInDomain, nl, 1);
2164 nlset(_UIKitBundle, nl, 2);
2165 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
2166 nlset(_UISharedImageNameGetIdentifier, nl, 4);
2168 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
2169 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
2170 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
2174 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
2175 NSError *error(nil);
2176 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
2177 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
2179 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);