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]:_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 MSClassHook(UINavigationBar)
122 MSClassHook(UIToolbar)
124 MSClassHook(CKMessageCell)
125 MSClassHook(CKTimestampView)
126 MSClassHook(CKTranscriptController)
127 MSClassHook(CKTranscriptTableView)
129 MSClassHook(SBApplication)
130 MSClassHook(SBApplicationIcon)
131 MSClassHook(SBAwayView)
132 MSClassHook(SBBookmarkIcon)
133 MSClassHook(SBButtonBar)
134 MSClassHook(SBCalendarIconContentsView)
135 MSClassHook(SBDockIconListView)
137 MSClassHook(SBIconBadge)
138 MSClassHook(SBIconController)
139 MSClassHook(SBIconLabel)
140 MSClassHook(SBIconList)
141 MSClassHook(SBIconModel)
142 //MSClassHook(SBImageCache)
143 MSClassHook(SBSearchView)
144 MSClassHook(SBSearchTableViewCell)
145 MSClassHook(SBStatusBarContentsView)
146 MSClassHook(SBStatusBarController)
147 MSClassHook(SBStatusBarOperatorNameView)
148 MSClassHook(SBStatusBarTimeView)
149 MSClassHook(SBUIController)
150 MSClassHook(SBWidgetApplicationIcon)
152 __attribute__((__constructor__))
153 static void MSFixClass() {
155 $SBIcon = objc_getClass("SBIconView");
156 if ($CKTranscriptController == nil)
157 $CKTranscriptController = objc_getClass("mSMSMessageTranscriptController");
161 static bool Four_($SBDockIconListView != nil);
163 @interface NSDictionary (WinterBoard)
164 - (UIColor *) wb$colorForKey:(NSString *)key;
165 - (BOOL) wb$boolForKey:(NSString *)key;
168 @implementation NSDictionary (WinterBoard)
170 - (UIColor *) wb$colorForKey:(NSString *)key {
171 NSString *value = [self objectForKey:key];
178 - (BOOL) wb$boolForKey:(NSString *)key {
179 if (NSString *value = [self objectForKey:key])
180 return [value boolValue];
186 static BOOL (*_GSFontGetUseLegacyFontMetrics)();
187 #define $GSFontGetUseLegacyFontMetrics() \
188 (_GSFontGetUseLegacyFontMetrics == NULL ? YES : _GSFontGetUseLegacyFontMetrics())
190 static bool Debug_ = false;
191 static bool Engineer_ = false;
192 static bool SummerBoard_ = true;
193 static bool SpringBoard_;
195 static UIImage *(*_UIApplicationImageWithName)(NSString *name);
196 static UIImage *(*_UIImageWithNameInDomain)(NSString *name, NSString *domain);
197 static NSBundle *(*_UIKitBundle)();
198 static bool (*_UIPackedImageTableGetIdentifierForName)(NSString *, int *);
199 static int (*_UISharedImageNameGetIdentifier)(NSString *);
201 static NSMutableDictionary *UIImages_ = [[NSMutableDictionary alloc] initWithCapacity:32];
202 static NSMutableDictionary *PathImages_ = [[NSMutableDictionary alloc] initWithCapacity:16];
203 static NSMutableDictionary *Cache_ = [[NSMutableDictionary alloc] initWithCapacity:64];
204 static NSMutableDictionary *Strings_ = [[NSMutableDictionary alloc] initWithCapacity:0];
205 static NSMutableDictionary *Bundles_ = [[NSMutableDictionary alloc] initWithCapacity:2];
207 static NSFileManager *Manager_;
208 static NSMutableArray *Themes_;
210 static NSDictionary *English_;
211 static NSMutableDictionary *Info_;
214 static NSMutableDictionary *Themed_ = [[NSMutableDictionary alloc] initWithCapacity:128];
216 static unsigned Scale_ = 0;
218 static unsigned $getScale$(NSString *path) {
219 NSString *name(path);
221 #define StripName(strip) \
222 if ([name hasSuffix:@ strip]) \
223 name = [name substringWithRange:NSMakeRange(0, [name length] - sizeof(strip) - 1)];
227 StripName("~iphone");
230 return [name hasSuffix:@"@2x"] ? 2 : 1;
233 static NSArray *$useScale$(NSArray *files, bool use = true) {
238 UIScreen *screen([UIScreen mainScreen]);
239 if ([screen respondsToSelector:@selector(scale)])
240 Scale_ = [screen scale];
248 NSMutableArray *scaled([NSMutableArray arrayWithCapacity:([files count] * 2)]);
250 for (NSString *file in files) {
251 [scaled addObject:[NSString stringWithFormat:@"%@@2x.%@", [file stringByDeletingPathExtension], [file pathExtension]]];
252 [scaled addObject:file];
258 static NSString *$getTheme$(NSArray *files, NSArray *themes = Themes_) {
259 if (NSString *path = [Themed_ objectForKey:files])
260 return reinterpret_cast<id>(path) == [NSNull null] ? nil : path;
263 NSLog(@"WB:Debug: %@", [files description]);
267 for (NSString *theme in Themes_)
268 for (NSString *file in files) {
269 path = [NSString stringWithFormat:@"%@/%@", theme, file];
270 if ([Manager_ fileExistsAtPath:path])
277 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:files];
281 // $pathForFile$inBundle$() {{{
282 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool ui) {
283 NSString *identifier = [bundle bundleIdentifier];
284 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
286 if (identifier != nil)
287 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
288 if (NSString *folder = [[bundle bundlePath] lastPathComponent])
289 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
291 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
293 #define remapResourceName(oldname, newname) \
294 else if ([file isEqualToString:(oldname)]) \
295 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
297 bool summer(SpringBoard_ && SummerBoard_);
299 if (identifier == nil);
300 else if ([identifier isEqualToString:@"com.apple.chatkit"])
301 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
302 else if ([identifier isEqualToString:@"com.apple.calculator"])
303 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
305 remapResourceName(@"FSO_BG.png", @"StatusBar")
306 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
307 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
309 if (NSString *path = $getTheme$($useScale$(names, ui)))
316 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
317 NSString *identifier = [self bundleIdentifier];
318 NSString *path = [self path];
319 NSString *folder = [path lastPathComponent];
320 NSString *dname = [self displayName];
321 NSString *didentifier = [self displayIdentifier];
324 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
326 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
328 /* XXX: I might need to keep this for backwards compatibility
329 if (identifier != nil)
330 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
332 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
334 #define testForIcon(Name) \
335 if (NSString *name = Name) \
336 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
338 if (![didentifier isEqualToString:identifier])
339 testForIcon(didentifier);
341 testForIcon(identifier);
344 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
347 if (didentifier != nil) {
348 testForIcon([English_ objectForKey:didentifier]);
350 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
351 if ([parts count] != 1)
352 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
353 testForIcon([english objectForKey:[parts lastObject]]);
356 if (NSString *path = $getTheme$(names))
362 // -[NSBundle wb$bundleWithFile] {{{
363 @interface NSBundle (WinterBoard)
364 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
367 @implementation NSBundle (WinterBoard)
369 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
370 path = [path stringByDeletingLastPathComponent];
371 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
374 NSBundle *bundle([Bundles_ objectForKey:path]);
375 if (reinterpret_cast<id>(bundle) == [NSNull null])
377 else if (bundle == nil) {
378 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
379 bundle = [NSBundle bundleWithPath:path];
381 bundle = [NSBundle wb$bundleWithFile:path];
383 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
384 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
392 // -[NSString wb$themedPath] {{{
393 @interface NSString (WinterBoard)
394 - (NSString *) wb$themedPath;
397 @implementation NSString (WinterBoard)
399 - (NSString *) wb$themedPath {
400 if ([self hasPrefix:@"/Library/Themes/"])
404 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
406 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
407 NSString *file([self stringByResolvingSymlinksInPath]);
408 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
409 if ([file hasPrefix:prefix]) {
410 NSUInteger length([prefix length]);
411 if (length != [file length])
412 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
423 void WBLogRect(const char *tag, struct CGRect rect) {
424 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
427 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
428 CGRect frame([view frame]);
429 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]);
431 for (UIView *child in [view subviews])
432 WBLogHierarchy(child, index++, indent + 1);
435 UIImage *$cacheForImage$(UIImage *image) {
436 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
437 CGRect rect = {CGPointMake(1, 1), [image size]};
438 CGSize size = {rect.size.width + 2, rect.size.height + 2};
440 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
441 CGColorSpaceRelease(space);
443 CGContextDrawImage(context, rect, [image CGImage]);
444 CGImageRef ref(CGBitmapContextCreateImage(context));
445 CGContextRelease(context);
447 UIImage *cache([UIImage imageWithCGImage:ref]);
453 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
454 //if ([name isEqualToString:@"icons"]) return nil;
455 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
458 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
459 NSString *key([icon displayIdentifier]);
461 if (UIImage *image = [icon icon]) {
462 CGSize size = [image size];
463 if (size.width != 59 || size.height != 60) {
464 UIImage *cache($cacheForImage$(image));
465 [Cache_ setObject:cache forKey:key];
470 _SBIconModel$cacheImageForIcon$(self, sel, icon);
473 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
474 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
475 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
477 NSString *key([icon displayIdentifier]);
479 if (UIImage *image = [icon icon]) {
480 CGSize size = [image size];
481 if (size.width != 59 || size.height != 60) {
482 UIImage *cache($cacheForImage$(image));
483 [Cache_ setObject:cache forKey:key];
489 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
490 NSString *key([icon displayIdentifier]);
491 if (UIImage *image = [Cache_ objectForKey:key])
494 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
497 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
499 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
500 NSString *key([icon displayIdentifier]);
501 if (UIImage *image = [Cache_ objectForKey:key])
504 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
507 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
508 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
509 [self setBackgroundColor:[UIColor clearColor]];
510 for (UIView *child in [self subviews])
511 [child setBackgroundColor:[UIColor clearColor]];
515 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
516 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
517 [self setBackgroundColor:[UIColor clearColor]];
521 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
522 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
523 float inset([self edgeInset]);
524 [[UIColor clearColor] set];
525 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
526 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
529 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
530 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
531 if (NSString *path = $pathForIcon$([self application]))
532 return [UIImage imageWithContentsOfFile:path];
533 return _SBApplicationIcon$icon(self, sel);
536 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
538 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
539 if (IsWild_ && false) // XXX: delete this code, it should not be supported
540 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
541 return [UIImage imageWithContentsOfFile:path72];
542 if (NSString *path = $pathForIcon$([self application]))
543 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
545 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
546 width = [$SBIcon defaultIconImageSize].width;
549 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
552 return _SBApplicationIcon$generateIconImage$(self, sel, type);
555 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
557 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
558 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
559 return [UIImage imageWithContentsOfFile:path];
560 return _SBWidgetApplicationIcon$icon(self, sel);
563 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
565 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
566 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
567 return [UIImage imageWithContentsOfFile:path];
568 return _SBBookmarkIcon$icon(self, sel);
571 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
572 if (NSString *path = $pathForIcon$(self))
574 return _SBApplication$pathForIcon(self, sel);
577 static UIImage *CachedImageAtPath(NSString *path) {
578 path = [path stringByResolvingSymlinksInPath];
579 UIImage *image = [PathImages_ objectForKey:path];
581 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
582 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
584 image = [image autorelease];
585 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
589 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
590 NSBundle *bundle = [NSBundle mainBundle];
592 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
593 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
594 return CachedImageAtPath(path);
595 return __UIApplicationImageWithName(name);
598 #define WBDelegate(delegate) \
599 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
601 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
602 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
604 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
608 - (void) forwardInvocation:(NSInvocation*)inv { \
609 SEL sel = [inv selector]; \
610 if ([delegate respondsToSelector:sel]) \
611 [inv invokeWithTarget:delegate]; \
613 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
616 // %hook -[NSBundle pathForResource:ofType:] {{{
617 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
618 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
620 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
621 if (NSString *path = $pathForFile$inBundle$(file, self, false))
623 return MSOldCall(resource, type);
627 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
628 NSBundle *bundle([NSBundle mainBundle]);
630 CFLocaleRef locale(CFLocaleCopyCurrent());
631 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
634 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
636 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
637 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
638 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
639 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
643 CFRelease(formatter);
645 NSString *datestyle([@""
646 "font-family: Helvetica; "
647 "font-weight: bold; "
650 "" stringByAppendingString:(IsWild_
651 ? @"font-size: 54px; "
652 : @"font-size: 39px; "
655 NSString *daystyle([@""
656 "font-family: Helvetica; "
657 "font-weight: bold; "
659 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
660 "" stringByAppendingString:(IsWild_
661 ? @"font-size: 11px; "
662 : @"font-size: 9px; "
665 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
666 datestyle = [datestyle stringByAppendingString:style];
667 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
668 daystyle = [daystyle stringByAppendingString:style];
670 float width([self bounds].size.width);
672 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
673 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
675 unsigned base0(IsWild_ ? 89 : 70);
676 if ($GSFontGetUseLegacyFontMetrics())
678 unsigned base1(IsWild_ ? 18 : 16);
685 [(NSString *)date drawAtPoint:CGPointMake(
686 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
687 ) withStyle:datestyle];
689 [(NSString *)day drawAtPoint:CGPointMake(
690 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
691 ) withStyle:daystyle];
697 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
698 void $setBarStyle$_(NSString *name, int &style) {
700 NSLog(@"WB:Debug:%@Style:%d", name, style);
701 NSNumber *number = nil;
703 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
705 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
707 style = [number intValue];
709 NSLog(@"WB:Debug:%@Style=%d", name, style);
713 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
714 $setBarStyle$_(@"Toolbar", style);
715 return MSOldCall(style);
718 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
719 $setBarStyle$_(@"NavigationBar", style);
720 return MSOldCall(style);
724 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
725 [[self superview] setBackgroundColor:[UIColor clearColor]];
726 _SBButtonBar$didMoveToSuperview(self, sel);
729 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
730 [[self superview] setBackgroundColor:[UIColor clearColor]];
731 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
734 MSHook(UIImage *, UIImage$defaultDesktopImage, UIImage *self, SEL sel) {
736 NSLog(@"WB:Debug:DefaultDesktopImage");
737 if (NSString *path = $getTheme$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil]))
738 return [UIImage imageWithContentsOfFile:path];
739 return _UIImage$defaultDesktopImage(self, sel);
742 static NSArray *Wallpapers_;
743 static bool Papered_;
745 static NSString *WallpaperFile_;
746 static UIImageView *WallpaperImage_;
747 static UIWebDocumentView *WallpaperPage_;
748 static NSURL *WallpaperURL_;
750 #define _release(object) \
751 do if (object != nil) { \
756 static UIImage *$getImage$(NSString *path) {
757 UIImage *image([UIImage imageWithContentsOfFile:path]);
759 unsigned scale($getScale$(path));
760 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
761 [image setScale:scale];
766 // %hook -[SBUIController init] {{{
767 MSInstanceMessageHook0(id, SBUIController, init) {
772 NSString *paper($getTheme$(Wallpapers_));
774 paper = [paper stringByDeletingLastPathComponent];
778 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
779 char *machine = new char[size];
781 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
782 perror("sysctlbyname(\"hw.machine\", ?)");
787 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
790 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
792 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
793 [Info_ setObject:[NSNumber numberWithBool:(
794 !(paper != nil || GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"))) ||
795 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
796 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
797 )] forKey:@"UndockedIconLabels"];
800 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
803 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
804 if (&_wallpaperView != NULL) {
805 [_wallpaperView removeFromSuperview];
806 [_wallpaperView release];
807 _wallpaperView = nil;
811 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
812 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
815 if (&_contentLayer != NULL)
816 player = &_contentLayer;
817 else if (&_contentView != NULL)
818 player = &_contentView;
821 UIView *layer(player == NULL ? nil : *player);
823 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
824 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
825 [window setContentView:content];
827 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
828 [window setBackgroundColor:[_window backgroundColor]];
829 [_window setBackgroundColor:[UIColor clearColor]];
831 [window setLevel:-1000];
832 [window setHidden:NO];
834 /*if (player != NULL)
837 [content setBackgroundColor:[layer backgroundColor]];
838 [layer setBackgroundColor:[UIColor clearColor]];
841 if (!SummerBoard_ || !IsWild_)
844 CGRect bounds([content bounds]);
845 bounds.origin.y = -30;
846 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
847 [content addSubview:indirect];
848 [indirect zoomToScale:2.4];
851 _release(WallpaperFile_);
852 _release(WallpaperImage_);
853 _release(WallpaperPage_);
854 _release(WallpaperURL_);
857 NSArray *themes([NSArray arrayWithObject:paper]);
859 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
863 static AVController *controller_(nil);
864 if (controller_ == nil) {
865 AVQueue *queue([AVQueue avQueue]);
866 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
869 AVQueue *queue([controller_ queue]);
871 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
872 [controller_ setLayer:[video _layer]];
874 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
875 [queue appendItem:item error:&error];
877 [controller_ play:&error];
878 #elif UseMPMoviePlayerController
879 NSURL *url([NSURL fileURLWithPath:path]);
880 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
881 controller.movieControlMode = MPMovieControlModeHidden;
884 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
885 [video setMovieWithPath:path];
886 [video setRepeatMode:1];
887 [video setRepeatGap:-1];
888 [video playFromBeginning];;
891 [indirect addSubview:video];
894 if (NSString *path = $getTheme$([NSArray arrayWithObjects:@"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", nil], themes)) {
895 if (UIImage *image = $getImage$(path)) {
896 WallpaperFile_ = [path retain];
897 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
898 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
899 [WallpaperImage_ setAlpha:[number floatValue]];
900 [indirect addSubview:WallpaperImage_];
904 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper@.html"], themes)) {
905 CGRect bounds = [indirect bounds];
907 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
908 [view setAutoresizes:true];
910 WallpaperPage_ = [view retain];
911 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
913 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
915 [view setBackgroundColor:[UIColor clearColor]];
916 if ([view respondsToSelector:@selector(setDrawsBackground:)])
917 [view setDrawsBackground:NO];
918 [[view webView] setDrawsBackground:NO];
920 [indirect addSubview:view];
924 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
925 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
926 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
927 if ([Manager_ fileExistsAtPath:html]) {
928 CGRect bounds = [indirect bounds];
930 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
931 [view setAutoresizes:true];
933 NSURL *url = [NSURL fileURLWithPath:html];
934 [view loadRequest:[NSURLRequest requestWithURL:url]];
936 [view setBackgroundColor:[UIColor clearColor]];
937 if ([view respondsToSelector:@selector(setDrawsBackground:)])
938 [view setDrawsBackground:NO];
939 [[view webView] setDrawsBackground:NO];
941 [indirect addSubview:view];
949 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
950 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
951 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
953 if (path != nil && _backgroundView != nil)
956 _SBAwayView$updateDesktopImage$(self, sel, image);
959 CGRect bounds = [self bounds];
961 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
962 [view setAutoresizes:true];
964 if (WallpaperPage_ != nil)
965 [WallpaperPage_ release];
966 WallpaperPage_ = [view retain];
968 if (WallpaperURL_ != nil)
969 [WallpaperURL_ release];
970 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
972 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
974 [[view webView] setDrawsBackground:false];
975 [view setBackgroundColor:[UIColor clearColor]];
977 [self insertSubview:view aboveSubview:_backgroundView];
981 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
982 extern "C" CGColorRef CGGStateGetFillColor(void *);
983 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
984 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
986 /* WBTimeLabel {{{ */
987 @interface WBTimeLabel : NSProxy {
989 _transient SBStatusBarTimeView *view_;
992 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
996 @implementation WBTimeLabel
1003 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1004 time_ = [time retain];
1009 - (NSString *) description {
1015 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1016 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1017 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1019 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1020 "font-family: Helvetica; "
1021 "font-weight: bold; "
1024 "%@", _mode ? @"white" : @"black", custom]];
1029 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1034 /* WBBadgeLabel {{{ */
1035 @interface WBBadgeLabel : NSProxy {
1039 - (id) initWithBadge:(NSString *)badge;
1040 - (NSString *) description;
1044 @implementation WBBadgeLabel
1051 - (id) initWithBadge:(NSString *)badge {
1052 badge_ = [badge retain];
1056 - (NSString *) description {
1057 return [badge_ description];
1062 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1063 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1064 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1065 "font-family: Helvetica; "
1066 "font-weight: bold; "
1074 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1081 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1082 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1083 alpha = [number floatValue];
1084 return MSOldCall(alpha);
1087 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1088 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1089 alpha = [number floatValue];
1090 return MSOldCall(alpha);
1093 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1094 if ((self = MSOldCall()) != nil) {
1095 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1096 // XXX: note: this is overridden above, which is silly
1097 float alpha([number floatValue]);
1098 [self setIconImageAlpha:alpha];
1099 [self setIconLabelAlpha:alpha];
1104 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1105 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1106 alpha = [number floatValue];
1107 return MSOldCall(alpha);
1111 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1112 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1113 id &_badge(MSHookIvar<id>(self, "_badge"));
1115 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1120 void SBStatusBarController$setStatusBarMode(int &mode) {
1122 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1123 if (mode < 100) // 104:hidden 105:glowing
1124 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1125 mode = [number intValue];
1128 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1129 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1130 SBStatusBarController$setStatusBarMode(mode);
1131 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1134 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1135 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1136 SBStatusBarController$setStatusBarMode(mode);
1137 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1140 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) {
1141 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1142 SBStatusBarController$setStatusBarMode(mode);
1143 //NSLog(@"mode=%u", mode);
1144 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1147 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1148 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1149 mode = [number intValue];
1150 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1153 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1154 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1156 NSLog(@"operatorNameStyle= %@", style);
1157 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1158 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1162 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1164 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1165 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1168 // XXX: replace this with [SBStatusBarTimeView tile]
1169 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1170 id &_time(MSHookIvar<id>(self, "_time"));
1171 if (_time != nil && [_time class] != [WBTimeLabel class])
1172 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1173 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1176 @interface UIView (WinterBoard)
1177 - (bool) wb$isWBImageView;
1178 - (void) wb$logHierarchy;
1181 @implementation UIView (WinterBoard)
1183 - (bool) wb$isWBImageView {
1187 - (void) wb$logHierarchy {
1188 WBLogHierarchy(self);
1193 @interface WBImageView : UIImageView {
1196 - (bool) wb$isWBImageView;
1197 - (void) wb$updateFrame;
1200 @implementation WBImageView
1202 - (bool) wb$isWBImageView {
1206 - (void) wb$updateFrame {
1207 CGRect frame([self frame]);
1210 for (UIView *view(self); ; ) {
1211 view = [view superview];
1214 frame.origin.y -= [view frame].origin.y;
1217 [self setFrame:frame];
1222 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1223 NSArray *subviews([self subviews]);
1224 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1225 if (view != nil && [view wb$isWBImageView])
1226 [view wb$updateFrame];
1227 _SBIconList$setFrame$(self, sel, frame);
1230 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1231 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1232 NSArray *lists([_iconModel iconLists]);
1234 for (unsigned i(0), e([lists count]); i != e; ++i)
1235 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]])) {
1236 SBIconList *list([lists objectAtIndex:i]);
1237 NSArray *subviews([list subviews]);
1239 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1240 if (view == nil || ![view wb$isWBImageView]) {
1241 view = [[[WBImageView alloc] init] autorelease];
1242 [list insertSubview:view atIndex:0];
1245 UIImage *image([UIImage imageWithContentsOfFile:path]);
1247 CGRect frame([view frame]);
1248 frame.size = [image size];
1249 [view setFrame:frame];
1251 [view setImage:image];
1252 [view wb$updateFrame];
1255 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1258 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1259 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1261 [self setClipsToBounds:NO];
1265 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1266 id &_label(MSHookIvar<id>(self, "_label"));
1267 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1269 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1270 [_label setInDock:docked];
1271 return _SBIconLabel$setInDock$(self, sel, docked);
1274 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1275 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1278 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1279 _SBDockIconListView$setFrame$(self, sel, frame);
1282 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1283 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1284 NSString *identifier = [self bundleIdentifier];
1285 NSLocale *locale = [NSLocale currentLocale];
1286 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1288 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1289 NSString *file = table == nil ? @"Localizable" : table;
1290 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1291 NSDictionary *strings;
1292 if ((strings = [Strings_ objectForKey:name]) != nil) {
1293 if (static_cast<id>(strings) != [NSNull null]) strings:
1294 if (NSString *value = [strings objectForKey:key])
1296 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1299 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1300 [Strings_ setObject:[strings autorelease] forKey:name];
1304 [Strings_ setObject:[NSNull null] forKey:name];
1305 return MSOldCall(key, value, table);
1308 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1309 MSClassHook(WebCoreFrameBridge)
1311 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1314 void **core(reinterpret_cast<void **>([node _node]));
1315 if (core == NULL || core[6] == NULL)
1317 return MSOldCall(node, width);
1321 MSInstanceMessageHook1(void, SBIconLabel, drawRect, CGRect, rect) {
1322 CGRect bounds = [self bounds];
1324 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1327 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1328 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1330 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1332 NSString *style = [NSString stringWithFormat:@""
1333 "font-family: Helvetica; "
1334 "font-weight: bold; "
1336 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1337 ? @"font-size: 12px; "
1338 : @"font-size: 11px; "
1342 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1344 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1346 bool ellipsis(false);
1347 float max = 75, width;
1349 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
1352 size_t length([label length]);
1353 float spacing((width - max) / (length - 1));
1355 if (spacing > 1.25) {
1357 label = [label substringToIndex:(length - 1)];
1361 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
1365 label = [label stringByAppendingString:@"..."];
1367 if (NSString *custom = [Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")])
1368 style = [style stringByAppendingString:custom];
1370 CGSize size = [label sizeWithStyle:style forWidth:bounds.size.width];
1371 [label drawAtPoint:CGPointMake((bounds.size.width - size.width) / 2, 0) withStyle:style];
1375 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1377 [balloon setBackgroundColor:[UIColor clearColor]];
1380 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1381 if ((self = MSOldCall(style, reuse)) != nil) {
1382 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1386 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1387 if ((self = MSOldCall(style, reuse)) != nil) {
1388 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1389 [_label setBackgroundColor:[UIColor clearColor]];
1393 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1394 MSOldCall(UITableViewCellSeparatorStyleNone);
1397 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1398 if ((self = MSOldCall(frame, style)) != nil) {
1399 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1403 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1406 if (NSString *path = $getTheme$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil]))
1407 if (UIImage *image = [[UIImage alloc] initWithContentsOfFile:path]) {
1408 [image autorelease];
1410 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1411 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1413 if (&_transcriptTable != NULL)
1414 table = _transcriptTable;
1415 else if (&_transcriptLayer != NULL)
1416 table = _transcriptLayer;
1420 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1421 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1424 [placard insertSubview:background atIndex:0];
1426 [table setBackgroundColor:[UIColor clearColor]];
1427 [placard insertSubview:background belowSubview:table];
1433 // %hook _UIImageWithName() {{{
1434 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1436 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1443 if (_UIPackedImageTableGetIdentifierForName != NULL)
1444 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1445 else if (_UISharedImageNameGetIdentifier != NULL) {
1446 identifier = _UISharedImageNameGetIdentifier(name);
1447 packed = identifier != -1;
1454 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1457 return __UIImageWithName(name);
1459 NSNumber *key([NSNumber numberWithInt:identifier]);
1460 UIImage *image([UIImages_ objectForKey:key]);
1462 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1463 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1464 image = $getImage$(path);
1465 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1466 return image == nil ? __UIImageWithName(name) : image;
1470 // %hook _UIImageWithNameInDomain() {{{
1471 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1472 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1473 UIImage *image([PathImages_ objectForKey:key]);
1475 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1477 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1478 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1479 image = $getImage$(path);
1480 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1481 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1485 // %hook GSFontCreateWithName() {{{
1486 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1488 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1489 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1490 name = [font UTF8String];
1491 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1492 // size *= [scale floatValue];
1493 return _GSFontCreateWithName(name, traits, size);
1497 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1498 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1500 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1502 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1504 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1505 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1507 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1510 NSString *path = [NSString stringWithUTF8String:a1];
1511 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1512 NSString *file = [path substringFromIndex:31];
1513 for (NSString *theme in Themes_) {
1514 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1515 if ([Manager_ fileExistsAtPath:path]) {
1516 strcpy(a1, [path UTF8String]);
1525 static void ChangeWallpaper(
1526 CFNotificationCenterRef center,
1530 CFDictionaryRef info
1533 NSLog(@"WB:Debug:ChangeWallpaper!");
1536 if (WallpaperFile_ != nil) {
1537 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1539 image = [image autorelease];
1542 if (WallpaperImage_ != nil)
1543 [WallpaperImage_ setImage:image];
1544 if (WallpaperPage_ != nil)
1545 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1549 #define WBRename(name, sel, imp) \
1550 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
1552 template <typename Type_>
1553 static void msset(Type_ &function, MSImageRef image, const char *name) {
1554 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1557 template <typename Type_>
1558 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1559 struct nlist &name(nl[index]);
1560 uintptr_t value(name.n_value);
1561 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1562 value |= 0x00000001;
1563 function = reinterpret_cast<Type_>(value);
1566 template <typename Type_>
1567 static void dlset(Type_ &function, const char *name) {
1568 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1571 // %hook CGImageReadCreateWithFile() {{{
1572 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1574 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1575 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1576 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1582 extern "C" void WKSetCurrentGraphicsContext(CGContextRef);
1584 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
1585 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1586 if (style == nil || [style length] == 0)
1587 style = @"font-family: Helvetica; font-size: 12px";
1588 return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
1591 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
1592 if (style == nil || [style length] == 0)
1593 style = @"font-family: Helvetica; font-size: 12px";
1594 return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width];
1597 static void SBInitialize() {
1598 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
1599 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
1601 _UIImage$defaultDesktopImage = MSHookMessage(object_getClass($UIImage), @selector(defaultDesktopImage), &$UIImage$defaultDesktopImage);
1604 WBRename(SBApplication, pathForIcon, pathForIcon);
1605 WBRename(SBApplicationIcon, icon, icon);
1606 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1609 WBRename(SBBookmarkIcon, icon, icon);
1610 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1611 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1612 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1613 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
1615 WBRename(SBWidgetApplicationIcon, icon, icon);
1617 WBRename(SBDockIconListView, setFrame:, setFrame$);
1618 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
1620 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
1621 WBRename(SBIconLabel, setInDock:, setInDock$);
1623 WBRename(SBIconList, setFrame:, setFrame$);
1625 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
1626 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
1627 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
1628 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
1630 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
1631 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
1632 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
1634 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
1636 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
1637 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
1638 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
1639 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
1640 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
1641 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
1642 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
1643 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
1644 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
1647 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
1651 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1653 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
1654 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
1656 Manager_ = [[NSFileManager defaultManager] retain];
1657 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
1659 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
1661 // Load Settings.plist {{{
1662 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
1663 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
1664 SummerBoard_ = [value boolValue];
1665 if (NSNumber *value = [settings objectForKey:@"Debug"])
1666 Debug_ = [value boolValue];
1668 NSArray *themes([settings objectForKey:@"Themes"]);
1670 if (NSString *theme = [settings objectForKey:@"Theme"])
1671 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
1673 [NSNumber numberWithBool:true], @"Active",
1677 for (NSDictionary *theme in themes) {
1678 NSNumber *active([theme objectForKey:@"Active"]);
1679 if (![active boolValue])
1682 NSString *name([theme objectForKey:@"Name"]);
1686 NSString *theme(nil);
1688 #define testForTheme(format...) \
1689 if (theme == nil) { \
1690 NSString *path = [NSString stringWithFormat:format]; \
1691 if ([Manager_ fileExistsAtPath:path]) { \
1692 [Themes_ addObject:path]; \
1697 testForTheme(@"/Library/Themes/%@.theme", name)
1698 testForTheme(@"/Library/Themes/%@", name)
1699 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
1704 // Merge Info.plist {{{
1705 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1707 for (NSString *theme in Themes_)
1708 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
1709 for (NSString *key in [info allKeys])
1710 if ([Info_ objectForKey:key] == nil)
1711 [Info_ setObject:[info objectForKey:key] forKey:key];
1715 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
1716 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
1717 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
1720 // GraphicsServices {{{
1722 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
1726 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
1727 void *(*CGImageReadCreateWithFile)(NSString *, int);
1728 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
1729 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
1734 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
1735 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]);
1737 CFNotificationCenterAddObserver(
1738 CFNotificationCenterGetDarwinNotifyCenter(),
1739 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
1742 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
1743 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
1744 if (MediaPlayer != nil)
1747 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
1748 $MPVideoView = objc_getClass("MPVideoView");
1755 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
1757 memset(nl, 0, sizeof(nl));
1758 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
1759 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
1760 nl[2].n_un.n_name = (char *) "__UIKitBundle";
1761 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
1762 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
1765 nlset(_UIApplicationImageWithName, nl, 0);
1766 nlset(_UIImageWithNameInDomain, nl, 1);
1767 nlset(_UIKitBundle, nl, 2);
1768 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
1769 nlset(_UISharedImageNameGetIdentifier, nl, 4);
1771 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
1772 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
1773 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);