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 extern "C" void __clear_cache (char *beg, char *end);
108 @protocol WinterBoard
112 Class $MPMoviePlayerController;
115 MSClassHook(NSBundle)
118 MSClassHook(UINavigationBar)
119 MSClassHook(UIToolbar)
121 MSClassHook(CKMessageCell)
122 MSClassHook(CKTimestampView)
123 MSClassHook(CKTranscriptController)
124 MSClassHook(CKTranscriptTableView)
126 MSClassHook(SBApplication)
127 MSClassHook(SBApplicationIcon)
128 MSClassHook(SBAwayView)
129 MSClassHook(SBBookmarkIcon)
130 MSClassHook(SBButtonBar)
131 MSClassHook(SBCalendarIconContentsView)
132 MSClassHook(SBDockIconListView)
134 MSClassHook(SBIconBadge)
135 MSClassHook(SBIconController)
136 MSClassHook(SBIconLabel)
137 MSClassHook(SBIconList)
138 MSClassHook(SBIconModel)
139 //MSClassHook(SBImageCache)
140 MSClassHook(SBSearchView)
141 MSClassHook(SBSearchTableViewCell)
142 MSClassHook(SBStatusBarContentsView)
143 MSClassHook(SBStatusBarController)
144 MSClassHook(SBStatusBarOperatorNameView)
145 MSClassHook(SBStatusBarTimeView)
146 MSClassHook(SBUIController)
147 MSClassHook(SBWidgetApplicationIcon)
149 __attribute__((__constructor__))
150 static void MSFixClass() {
152 $SBIcon = objc_getClass("SBIconView");
153 if ($CKTranscriptController == nil)
154 $CKTranscriptController = objc_getClass("mSMSMessageTranscriptController");
158 static bool Four_($SBDockIconListView != nil);
160 @interface NSDictionary (WinterBoard)
161 - (UIColor *) wb$colorForKey:(NSString *)key;
162 - (BOOL) wb$boolForKey:(NSString *)key;
165 @implementation NSDictionary (WinterBoard)
167 - (UIColor *) wb$colorForKey:(NSString *)key {
168 NSString *value = [self objectForKey:key];
175 - (BOOL) wb$boolForKey:(NSString *)key {
176 if (NSString *value = [self objectForKey:key])
177 return [value boolValue];
183 static BOOL (*_GSFontGetUseLegacyFontMetrics)();
184 #define $GSFontGetUseLegacyFontMetrics() \
185 (_GSFontGetUseLegacyFontMetrics == NULL ? YES : _GSFontGetUseLegacyFontMetrics())
187 static bool Debug_ = false;
188 static bool Engineer_ = false;
189 static bool SummerBoard_ = true;
190 static bool SpringBoard_;
192 static UIImage *(*_UIApplicationImageWithName)(NSString *name);
193 static UIImage *(*_UIImageWithNameInDomain)(NSString *name, NSString *domain);
194 static NSBundle *(*_UIKitBundle)();
195 static bool (*_UIPackedImageTableGetIdentifierForName)(NSString *, int *);
196 static int (*_UISharedImageNameGetIdentifier)(NSString *);
198 static NSMutableDictionary *UIImages_ = [[NSMutableDictionary alloc] initWithCapacity:32];
199 static NSMutableDictionary *PathImages_ = [[NSMutableDictionary alloc] initWithCapacity:16];
200 static NSMutableDictionary *Cache_ = [[NSMutableDictionary alloc] initWithCapacity:64];
201 static NSMutableDictionary *Strings_ = [[NSMutableDictionary alloc] initWithCapacity:0];
202 static NSMutableDictionary *Bundles_ = [[NSMutableDictionary alloc] initWithCapacity:2];
204 static NSFileManager *Manager_;
205 static NSMutableArray *Themes_;
207 static NSDictionary *English_;
208 static NSMutableDictionary *Info_;
211 static NSMutableDictionary *Themed_ = [[NSMutableDictionary alloc] initWithCapacity:128];
213 static unsigned Scale_ = 0;
215 static unsigned $getScale$(NSString *path) {
216 NSString *name(path);
218 #define StripName(strip) \
219 if ([name hasSuffix:@ strip]) \
220 name = [name substringWithRange:NSMakeRange(0, [name length] - sizeof(strip) - 1)];
224 StripName("~iphone");
227 return [name hasSuffix:@"@2x"] ? 2 : 1;
230 static NSString *$getTheme$(NSArray *files, bool rescale = false) {
231 if (NSString *path = [Themed_ objectForKey:files])
232 return reinterpret_cast<id>(path) == [NSNull null] ? nil : path;
234 if (rescale && Scale_ == 0) {
235 UIScreen *screen([UIScreen mainScreen]);
236 if ([screen respondsToSelector:@selector(scale)])
237 Scale_ = [screen scale];
243 NSLog(@"WB:Debug: %@", [files description]);
247 for (NSString *theme in Themes_)
248 for (NSString *file in files) {
249 if (rescale && /*$getScale$(file) == 1 &&*/ Scale_ == 2) {
250 path = [NSString stringWithFormat:@"%@/%@@2x.%@", theme, [file stringByDeletingPathExtension], [file pathExtension]];
251 if ([Manager_ fileExistsAtPath:path])
255 path = [NSString stringWithFormat:@"%@/%@", theme, file];
256 if ([Manager_ fileExistsAtPath:path])
263 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:files];
267 // $pathForFile$inBundle$() {{{
268 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool ui) {
269 NSString *identifier = [bundle bundleIdentifier];
270 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
272 if (identifier != nil)
273 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
274 if (NSString *folder = [[bundle bundlePath] lastPathComponent])
275 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
277 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
279 #define remapResourceName(oldname, newname) \
280 else if ([file isEqualToString:(oldname)]) \
281 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
283 bool summer(SpringBoard_ && SummerBoard_);
285 if (identifier == nil);
286 else if ([identifier isEqualToString:@"com.apple.chatkit"])
287 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
288 else if ([identifier isEqualToString:@"com.apple.calculator"])
289 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
291 remapResourceName(@"FSO_BG.png", @"StatusBar")
292 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
293 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
295 if (NSString *path = $getTheme$(names, ui))
302 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
303 NSString *identifier = [self bundleIdentifier];
304 NSString *path = [self path];
305 NSString *folder = [path lastPathComponent];
306 NSString *dname = [self displayName];
307 NSString *didentifier = [self displayIdentifier];
310 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
312 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
314 /* XXX: I might need to keep this for backwards compatibility
315 if (identifier != nil)
316 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
318 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
320 #define testForIcon(Name) \
321 if (NSString *name = Name) \
322 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
324 if (![didentifier isEqualToString:identifier])
325 testForIcon(didentifier);
327 testForIcon(identifier);
330 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
333 if (didentifier != nil) {
334 testForIcon([English_ objectForKey:didentifier]);
336 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
337 if ([parts count] != 1)
338 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
339 testForIcon([english objectForKey:[parts lastObject]]);
342 if (NSString *path = $getTheme$(names))
348 // -[NSBundle wb$bundleWithFile] {{{
349 @interface NSBundle (WinterBoard)
350 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
353 @implementation NSBundle (WinterBoard)
355 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
356 path = [path stringByDeletingLastPathComponent];
357 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
360 NSBundle *bundle([Bundles_ objectForKey:path]);
361 if (reinterpret_cast<id>(bundle) == [NSNull null])
363 else if (bundle == nil) {
364 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
365 bundle = [NSBundle bundleWithPath:path];
367 bundle = [NSBundle wb$bundleWithFile:path];
369 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
370 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
378 // -[NSString wb$themedPath] {{{
379 @interface NSString (WinterBoard)
380 - (NSString *) wb$themedPath;
383 @implementation NSString (WinterBoard)
385 - (NSString *) wb$themedPath {
387 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
389 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
390 NSString *file([self stringByResolvingSymlinksInPath]);
391 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
392 if ([file hasPrefix:prefix]) {
393 NSUInteger length([prefix length]);
394 if (length != [file length])
395 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
406 void WBLogRect(const char *tag, struct CGRect rect) {
407 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
410 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
411 CGRect frame([view frame]);
412 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]);
414 for (UIView *child in [view subviews])
415 WBLogHierarchy(child, index++, indent + 1);
418 UIImage *$cacheForImage$(UIImage *image) {
419 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
420 CGRect rect = {CGPointMake(1, 1), [image size]};
421 CGSize size = {rect.size.width + 2, rect.size.height + 2};
423 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
424 CGColorSpaceRelease(space);
426 CGContextDrawImage(context, rect, [image CGImage]);
427 CGImageRef ref(CGBitmapContextCreateImage(context));
428 CGContextRelease(context);
430 UIImage *cache([UIImage imageWithCGImage:ref]);
436 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
437 //if ([name isEqualToString:@"icons"]) return nil;
438 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
441 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
442 NSString *key([icon displayIdentifier]);
444 if (UIImage *image = [icon icon]) {
445 CGSize size = [image size];
446 if (size.width != 59 || size.height != 60) {
447 UIImage *cache($cacheForImage$(image));
448 [Cache_ setObject:cache forKey:key];
453 _SBIconModel$cacheImageForIcon$(self, sel, icon);
456 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
457 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
458 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
460 NSString *key([icon displayIdentifier]);
462 if (UIImage *image = [icon icon]) {
463 CGSize size = [image size];
464 if (size.width != 59 || size.height != 60) {
465 UIImage *cache($cacheForImage$(image));
466 [Cache_ setObject:cache forKey:key];
472 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
473 NSString *key([icon displayIdentifier]);
474 if (UIImage *image = [Cache_ objectForKey:key])
477 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
480 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
482 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
483 NSString *key([icon displayIdentifier]);
484 if (UIImage *image = [Cache_ objectForKey:key])
487 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
490 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
491 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
492 [self setBackgroundColor:[UIColor clearColor]];
493 for (UIView *child in [self subviews])
494 [child setBackgroundColor:[UIColor clearColor]];
498 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
499 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
500 [self setBackgroundColor:[UIColor clearColor]];
504 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
505 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
506 float inset([self edgeInset]);
507 [[UIColor clearColor] set];
508 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
509 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
512 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
513 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
514 if (NSString *path = $pathForIcon$([self application]))
515 return [UIImage imageWithContentsOfFile:path];
516 return _SBApplicationIcon$icon(self, sel);
519 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
521 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
522 if (IsWild_ && false) // XXX: delete this code, it should not be supported
523 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
524 return [UIImage imageWithContentsOfFile:path72];
525 if (NSString *path = $pathForIcon$([self application]))
526 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
528 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
529 width = [$SBIcon defaultIconImageSize].width;
532 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
535 return _SBApplicationIcon$generateIconImage$(self, sel, type);
538 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
540 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
541 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
542 return [UIImage imageWithContentsOfFile:path];
543 return _SBWidgetApplicationIcon$icon(self, sel);
546 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
548 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
549 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
550 return [UIImage imageWithContentsOfFile:path];
551 return _SBBookmarkIcon$icon(self, sel);
554 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
555 if (NSString *path = $pathForIcon$(self))
557 return _SBApplication$pathForIcon(self, sel);
560 static UIImage *CachedImageAtPath(NSString *path) {
561 path = [path stringByResolvingSymlinksInPath];
562 UIImage *image = [PathImages_ objectForKey:path];
564 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
565 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
567 image = [image autorelease];
568 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
572 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
573 NSBundle *bundle = [NSBundle mainBundle];
575 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
576 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
577 return CachedImageAtPath(path);
578 return __UIApplicationImageWithName(name);
581 #define WBDelegate(delegate) \
582 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
584 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
585 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
587 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
591 - (void) forwardInvocation:(NSInvocation*)inv { \
592 SEL sel = [inv selector]; \
593 if ([delegate respondsToSelector:sel]) \
594 [inv invokeWithTarget:delegate]; \
596 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
599 // %hook -[NSBundle pathForResource:ofType:] {{{
600 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
601 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
603 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
604 if (NSString *path = $pathForFile$inBundle$(file, self, false))
606 return MSOldCall(resource, type);
610 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
611 NSBundle *bundle([NSBundle mainBundle]);
613 CFLocaleRef locale(CFLocaleCopyCurrent());
614 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
617 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
619 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
620 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
621 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
622 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
626 CFRelease(formatter);
628 NSString *datestyle([@""
629 "font-family: Helvetica; "
630 "font-weight: bold; "
633 "" stringByAppendingString:(IsWild_
634 ? @"font-size: 54px; "
635 : @"font-size: 39px; "
638 NSString *daystyle([@""
639 "font-family: Helvetica; "
640 "font-weight: bold; "
642 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
643 "" stringByAppendingString:(IsWild_
644 ? @"font-size: 11px; "
645 : @"font-size: 9px; "
648 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
649 datestyle = [datestyle stringByAppendingString:style];
650 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
651 daystyle = [daystyle stringByAppendingString:style];
653 float width([self bounds].size.width);
655 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
656 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
658 unsigned base0(IsWild_ ? 89 : 70);
659 if ($GSFontGetUseLegacyFontMetrics())
661 unsigned base1(IsWild_ ? 18 : 16);
668 [(NSString *)date drawAtPoint:CGPointMake(
669 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
670 ) withStyle:datestyle];
672 [(NSString *)day drawAtPoint:CGPointMake(
673 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
674 ) withStyle:daystyle];
680 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
681 void $setBarStyle$_(NSString *name, int &style) {
683 NSLog(@"WB:Debug:%@Style:%d", name, style);
684 NSNumber *number = nil;
686 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
688 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
690 style = [number intValue];
692 NSLog(@"WB:Debug:%@Style=%d", name, style);
696 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
697 $setBarStyle$_(@"Toolbar", style);
698 return MSOldCall(style);
701 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
702 $setBarStyle$_(@"NavigationBar", style);
703 return MSOldCall(style);
707 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
708 [[self superview] setBackgroundColor:[UIColor clearColor]];
709 _SBButtonBar$didMoveToSuperview(self, sel);
712 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
713 [[self superview] setBackgroundColor:[UIColor clearColor]];
714 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
717 MSHook(UIImage *, UIImage$defaultDesktopImage, UIImage *self, SEL sel) {
719 NSLog(@"WB:Debug:DefaultDesktopImage");
720 if (NSString *path = $getTheme$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil]))
721 return [UIImage imageWithContentsOfFile:path];
722 return _UIImage$defaultDesktopImage(self, sel);
725 static NSArray *Wallpapers_;
726 static bool Papered_;
728 static NSString *WallpaperFile_;
729 static UIImageView *WallpaperImage_;
730 static UIWebDocumentView *WallpaperPage_;
731 static NSURL *WallpaperURL_;
733 #define _release(object) \
734 do if (object != nil) { \
739 static UIImage *$getImage$(NSString *path) {
740 UIImage *image([UIImage imageWithContentsOfFile:path]);
742 unsigned scale($getScale$(path));
743 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
744 [image setScale:scale];
749 // %hook -[SBUIController init] {{{
750 MSInstanceMessageHook0(id, SBUIController, init) {
755 NSString *paper($getTheme$(Wallpapers_, true));
759 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
760 char *machine = new char[size];
762 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
763 perror("sysctlbyname(\"hw.machine\", ?)");
768 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
771 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
773 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
774 [Info_ setObject:[NSNumber numberWithBool:(
775 !(paper != nil || GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"))) ||
776 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
777 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
778 )] forKey:@"UndockedIconLabels"];
781 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
784 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
785 if (&_wallpaperView != NULL) {
786 [_wallpaperView removeFromSuperview];
787 [_wallpaperView release];
788 _wallpaperView = nil;
792 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
793 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
796 if (&_contentLayer != NULL)
797 player = &_contentLayer;
798 else if (&_contentView != NULL)
799 player = &_contentView;
802 UIView *layer(player == NULL ? nil : *player);
804 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
805 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
806 [window setContentView:content];
808 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
809 [window setBackgroundColor:[_window backgroundColor]];
810 [_window setBackgroundColor:[UIColor clearColor]];
812 [window setLevel:-1000];
813 [window setHidden:NO];
815 /*if (player != NULL)
818 [content setBackgroundColor:[layer backgroundColor]];
819 [layer setBackgroundColor:[UIColor clearColor]];
822 if (!SummerBoard_ || !IsWild_)
825 CGRect bounds([content bounds]);
826 bounds.origin.y = -30;
827 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
828 [content addSubview:indirect];
829 [indirect zoomToScale:2.4];
832 _release(WallpaperFile_);
833 _release(WallpaperImage_);
834 _release(WallpaperPage_);
835 _release(WallpaperURL_);
837 if (NSString *path = paper) {
838 if ([path hasSuffix:@".mp4"]) {
842 static AVController *controller_(nil);
843 if (controller_ == nil) {
844 AVQueue *queue([AVQueue avQueue]);
845 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
848 AVQueue *queue([controller_ queue]);
850 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
851 [controller_ setLayer:[video _layer]];
853 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
854 [queue appendItem:item error:&error];
856 [controller_ play:&error];
857 #elif UseMPMoviePlayerController
858 NSURL *url([NSURL fileURLWithPath:path]);
859 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
860 controller.movieControlMode = MPMovieControlModeHidden;
863 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
864 [video setMovieWithPath:path];
865 [video setRepeatMode:1];
866 [video setRepeatGap:-1];
867 [video playFromBeginning];;
870 [indirect addSubview:video];
873 if ([path hasSuffix:@".png"] || [path hasSuffix:@".jpg"]) {
874 if (UIImage *image = $getImage$(path)) {
875 WallpaperFile_ = [path retain];
876 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
877 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
878 [WallpaperImage_ setAlpha:[number floatValue]];
879 [indirect addSubview:WallpaperImage_];
883 if ([path hasSuffix:@".html"]) {
884 CGRect bounds = [indirect bounds];
886 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
887 [view setAutoresizes:true];
889 WallpaperPage_ = [view retain];
890 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
892 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
894 [view setBackgroundColor:[UIColor clearColor]];
895 if ([view respondsToSelector:@selector(setDrawsBackground:)])
896 [view setDrawsBackground:NO];
897 [[view webView] setDrawsBackground:NO];
899 [indirect addSubview:view];
903 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
904 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
905 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
906 if ([Manager_ fileExistsAtPath:html]) {
907 CGRect bounds = [indirect bounds];
909 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
910 [view setAutoresizes:true];
912 NSURL *url = [NSURL fileURLWithPath:html];
913 [view loadRequest:[NSURLRequest requestWithURL:url]];
915 [view setBackgroundColor:[UIColor clearColor]];
916 if ([view respondsToSelector:@selector(setDrawsBackground:)])
917 [view setDrawsBackground:NO];
918 [[view webView] setDrawsBackground:NO];
920 [indirect addSubview:view];
928 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
929 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
930 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
932 if (path != nil && _backgroundView != nil)
935 _SBAwayView$updateDesktopImage$(self, sel, image);
938 CGRect bounds = [self bounds];
940 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
941 [view setAutoresizes:true];
943 if (WallpaperPage_ != nil)
944 [WallpaperPage_ release];
945 WallpaperPage_ = [view retain];
947 if (WallpaperURL_ != nil)
948 [WallpaperURL_ release];
949 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
951 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
953 [[view webView] setDrawsBackground:false];
954 [view setBackgroundColor:[UIColor clearColor]];
956 [self insertSubview:view aboveSubview:_backgroundView];
960 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
961 extern "C" CGColorRef CGGStateGetFillColor(void *);
962 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
963 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
965 /* WBTimeLabel {{{ */
966 @interface WBTimeLabel : NSProxy {
968 _transient SBStatusBarTimeView *view_;
971 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
975 @implementation WBTimeLabel
982 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
983 time_ = [time retain];
988 - (NSString *) description {
994 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
995 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
996 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
998 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
999 "font-family: Helvetica; "
1000 "font-weight: bold; "
1003 "%@", _mode ? @"white" : @"black", custom]];
1008 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1013 /* WBBadgeLabel {{{ */
1014 @interface WBBadgeLabel : NSProxy {
1018 - (id) initWithBadge:(NSString *)badge;
1019 - (NSString *) description;
1023 @implementation WBBadgeLabel
1030 - (id) initWithBadge:(NSString *)badge {
1031 badge_ = [badge retain];
1035 - (NSString *) description {
1036 return [badge_ description];
1041 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1042 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1043 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1044 "font-family: Helvetica; "
1045 "font-weight: bold; "
1053 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1060 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1061 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1062 alpha = [number floatValue];
1063 return MSOldCall(alpha);
1066 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1067 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1068 alpha = [number floatValue];
1069 return MSOldCall(alpha);
1072 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1073 if ((self = MSOldCall()) != nil) {
1074 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1075 // XXX: note: this is overridden above, which is silly
1076 float alpha([number floatValue]);
1077 [self setIconImageAlpha:alpha];
1078 [self setIconLabelAlpha:alpha];
1083 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1084 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1085 alpha = [number floatValue];
1086 return MSOldCall(alpha);
1090 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1091 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1092 id &_badge(MSHookIvar<id>(self, "_badge"));
1094 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1099 void SBStatusBarController$setStatusBarMode(int &mode) {
1101 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1102 if (mode < 100) // 104:hidden 105:glowing
1103 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1104 mode = [number intValue];
1107 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1108 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1109 SBStatusBarController$setStatusBarMode(mode);
1110 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1113 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1114 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1115 SBStatusBarController$setStatusBarMode(mode);
1116 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1119 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) {
1120 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1121 SBStatusBarController$setStatusBarMode(mode);
1122 //NSLog(@"mode=%u", mode);
1123 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1126 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1127 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1128 mode = [number intValue];
1129 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1132 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1133 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1135 NSLog(@"operatorNameStyle= %@", style);
1136 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1137 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1141 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1143 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1144 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1147 // XXX: replace this with [SBStatusBarTimeView tile]
1148 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1149 id &_time(MSHookIvar<id>(self, "_time"));
1150 if (_time != nil && [_time class] != [WBTimeLabel class])
1151 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1152 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1155 @interface UIView (WinterBoard)
1156 - (bool) wb$isWBImageView;
1157 - (void) wb$logHierarchy;
1160 @implementation UIView (WinterBoard)
1162 - (bool) wb$isWBImageView {
1166 - (void) wb$logHierarchy {
1167 WBLogHierarchy(self);
1172 @interface WBImageView : UIImageView {
1175 - (bool) wb$isWBImageView;
1176 - (void) wb$updateFrame;
1179 @implementation WBImageView
1181 - (bool) wb$isWBImageView {
1185 - (void) wb$updateFrame {
1186 CGRect frame([self frame]);
1189 for (UIView *view(self); ; ) {
1190 view = [view superview];
1193 frame.origin.y -= [view frame].origin.y;
1196 [self setFrame:frame];
1201 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1202 NSArray *subviews([self subviews]);
1203 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1204 if (view != nil && [view wb$isWBImageView])
1205 [view wb$updateFrame];
1206 _SBIconList$setFrame$(self, sel, frame);
1209 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1210 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1211 NSArray *lists([_iconModel iconLists]);
1213 for (unsigned i(0), e([lists count]); i != e; ++i)
1214 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]])) {
1215 SBIconList *list([lists objectAtIndex:i]);
1216 NSArray *subviews([list subviews]);
1218 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1219 if (view == nil || ![view wb$isWBImageView]) {
1220 view = [[[WBImageView alloc] init] autorelease];
1221 [list insertSubview:view atIndex:0];
1224 UIImage *image([UIImage imageWithContentsOfFile:path]);
1226 CGRect frame([view frame]);
1227 frame.size = [image size];
1228 [view setFrame:frame];
1230 [view setImage:image];
1231 [view wb$updateFrame];
1234 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1237 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1238 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1240 [self setClipsToBounds:NO];
1244 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1245 id &_label(MSHookIvar<id>(self, "_label"));
1246 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1248 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1249 [_label setInDock:docked];
1250 return _SBIconLabel$setInDock$(self, sel, docked);
1253 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1254 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1257 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1258 _SBDockIconListView$setFrame$(self, sel, frame);
1261 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1262 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1263 NSString *identifier = [self bundleIdentifier];
1264 NSLocale *locale = [NSLocale currentLocale];
1265 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1267 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1268 NSString *file = table == nil ? @"Localizable" : table;
1269 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1270 NSDictionary *strings;
1271 if ((strings = [Strings_ objectForKey:name]) != nil) {
1272 if (static_cast<id>(strings) != [NSNull null]) strings:
1273 if (NSString *value = [strings objectForKey:key])
1275 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1278 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1279 [Strings_ setObject:[strings autorelease] forKey:name];
1283 [Strings_ setObject:[NSNull null] forKey:name];
1284 return MSOldCall(key, value, table);
1287 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1288 MSClassHook(WebCoreFrameBridge)
1290 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1293 void **core(reinterpret_cast<void **>([node _node]));
1294 if (core == NULL || core[6] == NULL)
1296 return MSOldCall(node, width);
1300 MSHook(void, SBIconLabel$drawRect$, SBIconLabel *self, SEL sel, CGRect rect) {
1301 CGRect bounds = [self bounds];
1303 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1306 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1307 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1309 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1311 NSString *style = [NSString stringWithFormat:@""
1312 "font-family: Helvetica; "
1313 "font-weight: bold; "
1315 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1316 ? @"font-size: 12px; "
1317 : @"font-size: 11px; "
1321 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1323 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1325 bool ellipsis(false);
1326 float max = 75, width;
1328 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
1331 size_t length([label length]);
1332 float spacing((width - max) / (length - 1));
1334 if (spacing > 1.25) {
1336 label = [label substringToIndex:(length - 1)];
1340 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
1344 label = [label stringByAppendingString:@"..."];
1346 if (NSString *custom = [Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")])
1347 style = [style stringByAppendingString:custom];
1349 CGSize size = [label sizeWithStyle:style forWidth:bounds.size.width];
1350 [label drawAtPoint:CGPointMake((bounds.size.width - size.width) / 2, 0) withStyle:style];
1354 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1356 [balloon setBackgroundColor:[UIColor clearColor]];
1359 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1360 if ((self = MSOldCall(style, reuse)) != nil) {
1361 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1365 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1366 if ((self = MSOldCall(style, reuse)) != nil) {
1367 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1368 [_label setBackgroundColor:[UIColor clearColor]];
1372 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1373 MSOldCall(UITableViewCellSeparatorStyleNone);
1376 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1377 if ((self = MSOldCall(frame, style)) != nil) {
1378 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1382 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1385 if (NSString *path = $getTheme$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil]))
1386 if (UIImage *image = [[UIImage alloc] initWithContentsOfFile:path]) {
1387 [image autorelease];
1389 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1390 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1392 if (&_transcriptTable != NULL)
1393 table = _transcriptTable;
1394 else if (&_transcriptLayer != NULL)
1395 table = _transcriptLayer;
1399 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1400 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1403 [placard insertSubview:background atIndex:0];
1405 [table setBackgroundColor:[UIColor clearColor]];
1406 [placard insertSubview:background belowSubview:table];
1412 // %hook _UIImageWithName() {{{
1413 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1415 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1422 if (_UIPackedImageTableGetIdentifierForName != NULL)
1423 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1424 else if (_UISharedImageNameGetIdentifier != NULL) {
1425 identifier = _UISharedImageNameGetIdentifier(name);
1426 packed = identifier != -1;
1433 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1436 return __UIImageWithName(name);
1438 NSNumber *key([NSNumber numberWithInt:identifier]);
1439 UIImage *image([UIImages_ objectForKey:key]);
1441 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1442 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true)) {
1443 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
1445 [image autorelease];
1447 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1448 return image == nil ? __UIImageWithName(name) : image;
1452 // %hook _UIImageWithNameInDomain() {{{
1453 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1454 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1455 UIImage *image([PathImages_ objectForKey:key]);
1457 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1459 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1460 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]], true)) {
1461 image = [[UIImage alloc] initWithContentsOfFile:path];
1463 [image autorelease];
1465 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1466 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1470 // %hook GSFontCreateWithName() {{{
1471 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1473 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1474 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1475 name = [font UTF8String];
1476 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1477 // size *= [scale floatValue];
1478 return _GSFontCreateWithName(name, traits, size);
1482 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1483 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1485 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1487 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1489 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1490 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1492 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1495 NSString *path = [NSString stringWithUTF8String:a1];
1496 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1497 NSString *file = [path substringFromIndex:31];
1498 for (NSString *theme in Themes_) {
1499 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1500 if ([Manager_ fileExistsAtPath:path]) {
1501 strcpy(a1, [path UTF8String]);
1510 static void ChangeWallpaper(
1511 CFNotificationCenterRef center,
1515 CFDictionaryRef info
1518 NSLog(@"WB:Debug:ChangeWallpaper!");
1521 if (WallpaperFile_ != nil) {
1522 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1524 image = [image autorelease];
1527 if (WallpaperImage_ != nil)
1528 [WallpaperImage_ setImage:image];
1529 if (WallpaperPage_ != nil)
1530 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1534 #define WBRename(name, sel, imp) \
1535 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
1537 template <typename Type_>
1538 static void msset(Type_ &function, MSImageRef image, const char *name) {
1539 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1542 template <typename Type_>
1543 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1544 struct nlist &name(nl[index]);
1545 uintptr_t value(name.n_value);
1546 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1547 value |= 0x00000001;
1548 function = reinterpret_cast<Type_>(value);
1551 template <typename Type_>
1552 static void dlset(Type_ &function, const char *name) {
1553 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1556 // %hook CGImageReadCreateWithFile() {{{
1557 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1559 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1560 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1561 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1567 static void SBInitialize() {
1568 _UIImage$defaultDesktopImage = MSHookMessage(object_getClass($UIImage), @selector(defaultDesktopImage), &$UIImage$defaultDesktopImage);
1570 bool olden(dlsym(RTLD_DEFAULT, "GSLibraryCopyGenerationInfoValueForKey") == NULL);
1573 WBRename(SBApplication, pathForIcon, pathForIcon);
1574 WBRename(SBApplicationIcon, icon, icon);
1575 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1578 WBRename(SBBookmarkIcon, icon, icon);
1579 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1580 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1581 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1582 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
1584 WBRename(SBWidgetApplicationIcon, icon, icon);
1586 WBRename(SBDockIconListView, setFrame:, setFrame$);
1587 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
1590 WBRename(SBIconLabel, drawRect:, drawRect$);
1592 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
1593 WBRename(SBIconLabel, setInDock:, setInDock$);
1595 WBRename(SBIconList, setFrame:, setFrame$);
1597 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
1598 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
1599 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
1600 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
1602 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
1603 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
1604 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
1606 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
1608 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
1609 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
1610 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
1611 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
1612 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
1613 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
1614 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
1615 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
1616 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
1619 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
1623 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1625 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
1626 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
1628 Manager_ = [[NSFileManager defaultManager] retain];
1629 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
1631 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
1633 // Load Settings.plist {{{
1634 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
1635 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
1636 SummerBoard_ = [value boolValue];
1637 if (NSNumber *value = [settings objectForKey:@"Debug"])
1638 Debug_ = [value boolValue];
1640 NSArray *themes([settings objectForKey:@"Themes"]);
1642 if (NSString *theme = [settings objectForKey:@"Theme"])
1643 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
1645 [NSNumber numberWithBool:true], @"Active",
1649 for (NSDictionary *theme in themes) {
1650 NSNumber *active([theme objectForKey:@"Active"]);
1651 if (![active boolValue])
1654 NSString *name([theme objectForKey:@"Name"]);
1658 NSString *theme(nil);
1660 #define testForTheme(format...) \
1661 if (theme == nil) { \
1662 NSString *path = [NSString stringWithFormat:format]; \
1663 if ([Manager_ fileExistsAtPath:path]) { \
1664 [Themes_ addObject:path]; \
1669 testForTheme(@"/Library/Themes/%@.theme", name)
1670 testForTheme(@"/Library/Themes/%@", name)
1671 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
1676 // Merge Info.plist {{{
1677 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1679 for (NSString *theme in Themes_)
1680 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
1681 for (NSString *key in [info allKeys])
1682 if ([Info_ objectForKey:key] == nil)
1683 [Info_ setObject:[info objectForKey:key] forKey:key];
1687 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
1688 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
1689 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
1692 // GraphicsServices {{{
1694 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
1698 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
1699 void *(*CGImageReadCreateWithFile)(NSString *, int);
1700 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
1701 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
1706 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
1707 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]);
1709 CFNotificationCenterAddObserver(
1710 CFNotificationCenterGetDarwinNotifyCenter(),
1711 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
1714 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
1715 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
1716 if (MediaPlayer != nil)
1719 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
1720 $MPVideoView = objc_getClass("MPVideoView");
1727 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
1729 memset(nl, 0, sizeof(nl));
1730 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
1731 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
1732 nl[2].n_un.n_name = (char *) "__UIKitBundle";
1733 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
1734 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
1737 nlset(_UIApplicationImageWithName, nl, 0);
1738 nlset(_UIImageWithNameInDomain, nl, 1);
1739 nlset(_UIKitBundle, nl, 2);
1740 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
1741 nlset(_UISharedImageNameGetIdentifier, nl, 4);
1743 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
1744 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
1745 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);