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 {
386 if ([self hasPrefix:@"/Library/Themes/"])
390 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
392 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
393 NSString *file([self stringByResolvingSymlinksInPath]);
394 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
395 if ([file hasPrefix:prefix]) {
396 NSUInteger length([prefix length]);
397 if (length != [file length])
398 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
409 void WBLogRect(const char *tag, struct CGRect rect) {
410 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
413 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
414 CGRect frame([view frame]);
415 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]);
417 for (UIView *child in [view subviews])
418 WBLogHierarchy(child, index++, indent + 1);
421 UIImage *$cacheForImage$(UIImage *image) {
422 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
423 CGRect rect = {CGPointMake(1, 1), [image size]};
424 CGSize size = {rect.size.width + 2, rect.size.height + 2};
426 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
427 CGColorSpaceRelease(space);
429 CGContextDrawImage(context, rect, [image CGImage]);
430 CGImageRef ref(CGBitmapContextCreateImage(context));
431 CGContextRelease(context);
433 UIImage *cache([UIImage imageWithCGImage:ref]);
439 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
440 //if ([name isEqualToString:@"icons"]) return nil;
441 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
444 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
445 NSString *key([icon displayIdentifier]);
447 if (UIImage *image = [icon icon]) {
448 CGSize size = [image size];
449 if (size.width != 59 || size.height != 60) {
450 UIImage *cache($cacheForImage$(image));
451 [Cache_ setObject:cache forKey:key];
456 _SBIconModel$cacheImageForIcon$(self, sel, icon);
459 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
460 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
461 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
463 NSString *key([icon displayIdentifier]);
465 if (UIImage *image = [icon icon]) {
466 CGSize size = [image size];
467 if (size.width != 59 || size.height != 60) {
468 UIImage *cache($cacheForImage$(image));
469 [Cache_ setObject:cache forKey:key];
475 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
476 NSString *key([icon displayIdentifier]);
477 if (UIImage *image = [Cache_ objectForKey:key])
480 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
483 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
485 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
486 NSString *key([icon displayIdentifier]);
487 if (UIImage *image = [Cache_ objectForKey:key])
490 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
493 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
494 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
495 [self setBackgroundColor:[UIColor clearColor]];
496 for (UIView *child in [self subviews])
497 [child setBackgroundColor:[UIColor clearColor]];
501 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
502 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
503 [self setBackgroundColor:[UIColor clearColor]];
507 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
508 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
509 float inset([self edgeInset]);
510 [[UIColor clearColor] set];
511 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
512 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
515 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
516 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
517 if (NSString *path = $pathForIcon$([self application]))
518 return [UIImage imageWithContentsOfFile:path];
519 return _SBApplicationIcon$icon(self, sel);
522 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
524 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
525 if (IsWild_ && false) // XXX: delete this code, it should not be supported
526 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
527 return [UIImage imageWithContentsOfFile:path72];
528 if (NSString *path = $pathForIcon$([self application]))
529 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
531 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
532 width = [$SBIcon defaultIconImageSize].width;
535 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
538 return _SBApplicationIcon$generateIconImage$(self, sel, type);
541 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
543 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
544 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
545 return [UIImage imageWithContentsOfFile:path];
546 return _SBWidgetApplicationIcon$icon(self, sel);
549 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
551 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
552 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
553 return [UIImage imageWithContentsOfFile:path];
554 return _SBBookmarkIcon$icon(self, sel);
557 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
558 if (NSString *path = $pathForIcon$(self))
560 return _SBApplication$pathForIcon(self, sel);
563 static UIImage *CachedImageAtPath(NSString *path) {
564 path = [path stringByResolvingSymlinksInPath];
565 UIImage *image = [PathImages_ objectForKey:path];
567 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
568 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
570 image = [image autorelease];
571 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
575 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
576 NSBundle *bundle = [NSBundle mainBundle];
578 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
579 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
580 return CachedImageAtPath(path);
581 return __UIApplicationImageWithName(name);
584 #define WBDelegate(delegate) \
585 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
587 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
588 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
590 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
594 - (void) forwardInvocation:(NSInvocation*)inv { \
595 SEL sel = [inv selector]; \
596 if ([delegate respondsToSelector:sel]) \
597 [inv invokeWithTarget:delegate]; \
599 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
602 // %hook -[NSBundle pathForResource:ofType:] {{{
603 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
604 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
606 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
607 if (NSString *path = $pathForFile$inBundle$(file, self, false))
609 return MSOldCall(resource, type);
613 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
614 NSBundle *bundle([NSBundle mainBundle]);
616 CFLocaleRef locale(CFLocaleCopyCurrent());
617 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
620 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
622 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
623 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
624 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
625 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
629 CFRelease(formatter);
631 NSString *datestyle([@""
632 "font-family: Helvetica; "
633 "font-weight: bold; "
636 "" stringByAppendingString:(IsWild_
637 ? @"font-size: 54px; "
638 : @"font-size: 39px; "
641 NSString *daystyle([@""
642 "font-family: Helvetica; "
643 "font-weight: bold; "
645 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
646 "" stringByAppendingString:(IsWild_
647 ? @"font-size: 11px; "
648 : @"font-size: 9px; "
651 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
652 datestyle = [datestyle stringByAppendingString:style];
653 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
654 daystyle = [daystyle stringByAppendingString:style];
656 float width([self bounds].size.width);
658 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
659 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
661 unsigned base0(IsWild_ ? 89 : 70);
662 if ($GSFontGetUseLegacyFontMetrics())
664 unsigned base1(IsWild_ ? 18 : 16);
671 [(NSString *)date drawAtPoint:CGPointMake(
672 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
673 ) withStyle:datestyle];
675 [(NSString *)day drawAtPoint:CGPointMake(
676 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
677 ) withStyle:daystyle];
683 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
684 void $setBarStyle$_(NSString *name, int &style) {
686 NSLog(@"WB:Debug:%@Style:%d", name, style);
687 NSNumber *number = nil;
689 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
691 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
693 style = [number intValue];
695 NSLog(@"WB:Debug:%@Style=%d", name, style);
699 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
700 $setBarStyle$_(@"Toolbar", style);
701 return MSOldCall(style);
704 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
705 $setBarStyle$_(@"NavigationBar", style);
706 return MSOldCall(style);
710 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
711 [[self superview] setBackgroundColor:[UIColor clearColor]];
712 _SBButtonBar$didMoveToSuperview(self, sel);
715 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
716 [[self superview] setBackgroundColor:[UIColor clearColor]];
717 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
720 MSHook(UIImage *, UIImage$defaultDesktopImage, UIImage *self, SEL sel) {
722 NSLog(@"WB:Debug:DefaultDesktopImage");
723 if (NSString *path = $getTheme$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil]))
724 return [UIImage imageWithContentsOfFile:path];
725 return _UIImage$defaultDesktopImage(self, sel);
728 static NSArray *Wallpapers_;
729 static bool Papered_;
731 static NSString *WallpaperFile_;
732 static UIImageView *WallpaperImage_;
733 static UIWebDocumentView *WallpaperPage_;
734 static NSURL *WallpaperURL_;
736 #define _release(object) \
737 do if (object != nil) { \
742 static UIImage *$getImage$(NSString *path) {
743 UIImage *image([UIImage imageWithContentsOfFile:path]);
745 unsigned scale($getScale$(path));
746 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
747 [image setScale:scale];
752 // %hook -[SBUIController init] {{{
753 MSInstanceMessageHook0(id, SBUIController, init) {
758 NSString *paper($getTheme$(Wallpapers_, true));
762 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
763 char *machine = new char[size];
765 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
766 perror("sysctlbyname(\"hw.machine\", ?)");
771 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
774 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
776 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
777 [Info_ setObject:[NSNumber numberWithBool:(
778 !(paper != nil || GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"))) ||
779 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
780 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
781 )] forKey:@"UndockedIconLabels"];
784 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
787 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
788 if (&_wallpaperView != NULL) {
789 [_wallpaperView removeFromSuperview];
790 [_wallpaperView release];
791 _wallpaperView = nil;
795 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
796 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
799 if (&_contentLayer != NULL)
800 player = &_contentLayer;
801 else if (&_contentView != NULL)
802 player = &_contentView;
805 UIView *layer(player == NULL ? nil : *player);
807 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
808 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
809 [window setContentView:content];
811 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
812 [window setBackgroundColor:[_window backgroundColor]];
813 [_window setBackgroundColor:[UIColor clearColor]];
815 [window setLevel:-1000];
816 [window setHidden:NO];
818 /*if (player != NULL)
821 [content setBackgroundColor:[layer backgroundColor]];
822 [layer setBackgroundColor:[UIColor clearColor]];
825 if (!SummerBoard_ || !IsWild_)
828 CGRect bounds([content bounds]);
829 bounds.origin.y = -30;
830 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
831 [content addSubview:indirect];
832 [indirect zoomToScale:2.4];
835 _release(WallpaperFile_);
836 _release(WallpaperImage_);
837 _release(WallpaperPage_);
838 _release(WallpaperURL_);
840 if (NSString *path = paper) {
841 if ([path hasSuffix:@".mp4"]) {
845 static AVController *controller_(nil);
846 if (controller_ == nil) {
847 AVQueue *queue([AVQueue avQueue]);
848 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
851 AVQueue *queue([controller_ queue]);
853 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
854 [controller_ setLayer:[video _layer]];
856 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
857 [queue appendItem:item error:&error];
859 [controller_ play:&error];
860 #elif UseMPMoviePlayerController
861 NSURL *url([NSURL fileURLWithPath:path]);
862 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
863 controller.movieControlMode = MPMovieControlModeHidden;
866 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
867 [video setMovieWithPath:path];
868 [video setRepeatMode:1];
869 [video setRepeatGap:-1];
870 [video playFromBeginning];;
873 [indirect addSubview:video];
876 if ([path hasSuffix:@".png"] || [path hasSuffix:@".jpg"]) {
877 if (UIImage *image = $getImage$(path)) {
878 WallpaperFile_ = [path retain];
879 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
880 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
881 [WallpaperImage_ setAlpha:[number floatValue]];
882 [indirect addSubview:WallpaperImage_];
886 if ([path hasSuffix:@".html"]) {
887 CGRect bounds = [indirect bounds];
889 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
890 [view setAutoresizes:true];
892 WallpaperPage_ = [view retain];
893 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
895 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
897 [view setBackgroundColor:[UIColor clearColor]];
898 if ([view respondsToSelector:@selector(setDrawsBackground:)])
899 [view setDrawsBackground:NO];
900 [[view webView] setDrawsBackground:NO];
902 [indirect addSubview:view];
906 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
907 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
908 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
909 if ([Manager_ fileExistsAtPath:html]) {
910 CGRect bounds = [indirect bounds];
912 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
913 [view setAutoresizes:true];
915 NSURL *url = [NSURL fileURLWithPath:html];
916 [view loadRequest:[NSURLRequest requestWithURL:url]];
918 [view setBackgroundColor:[UIColor clearColor]];
919 if ([view respondsToSelector:@selector(setDrawsBackground:)])
920 [view setDrawsBackground:NO];
921 [[view webView] setDrawsBackground:NO];
923 [indirect addSubview:view];
931 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
932 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
933 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
935 if (path != nil && _backgroundView != nil)
938 _SBAwayView$updateDesktopImage$(self, sel, image);
941 CGRect bounds = [self bounds];
943 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
944 [view setAutoresizes:true];
946 if (WallpaperPage_ != nil)
947 [WallpaperPage_ release];
948 WallpaperPage_ = [view retain];
950 if (WallpaperURL_ != nil)
951 [WallpaperURL_ release];
952 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
954 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
956 [[view webView] setDrawsBackground:false];
957 [view setBackgroundColor:[UIColor clearColor]];
959 [self insertSubview:view aboveSubview:_backgroundView];
963 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
964 extern "C" CGColorRef CGGStateGetFillColor(void *);
965 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
966 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
968 /* WBTimeLabel {{{ */
969 @interface WBTimeLabel : NSProxy {
971 _transient SBStatusBarTimeView *view_;
974 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
978 @implementation WBTimeLabel
985 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
986 time_ = [time retain];
991 - (NSString *) description {
997 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
998 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
999 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1001 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1002 "font-family: Helvetica; "
1003 "font-weight: bold; "
1006 "%@", _mode ? @"white" : @"black", custom]];
1011 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1016 /* WBBadgeLabel {{{ */
1017 @interface WBBadgeLabel : NSProxy {
1021 - (id) initWithBadge:(NSString *)badge;
1022 - (NSString *) description;
1026 @implementation WBBadgeLabel
1033 - (id) initWithBadge:(NSString *)badge {
1034 badge_ = [badge retain];
1038 - (NSString *) description {
1039 return [badge_ description];
1044 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1045 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1046 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1047 "font-family: Helvetica; "
1048 "font-weight: bold; "
1056 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1063 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1064 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1065 alpha = [number floatValue];
1066 return MSOldCall(alpha);
1069 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1070 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1071 alpha = [number floatValue];
1072 return MSOldCall(alpha);
1075 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1076 if ((self = MSOldCall()) != nil) {
1077 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1078 // XXX: note: this is overridden above, which is silly
1079 float alpha([number floatValue]);
1080 [self setIconImageAlpha:alpha];
1081 [self setIconLabelAlpha:alpha];
1086 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1087 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1088 alpha = [number floatValue];
1089 return MSOldCall(alpha);
1093 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1094 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1095 id &_badge(MSHookIvar<id>(self, "_badge"));
1097 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1102 void SBStatusBarController$setStatusBarMode(int &mode) {
1104 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1105 if (mode < 100) // 104:hidden 105:glowing
1106 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1107 mode = [number intValue];
1110 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1111 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1112 SBStatusBarController$setStatusBarMode(mode);
1113 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1116 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1117 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1118 SBStatusBarController$setStatusBarMode(mode);
1119 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1122 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) {
1123 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1124 SBStatusBarController$setStatusBarMode(mode);
1125 //NSLog(@"mode=%u", mode);
1126 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1129 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1130 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1131 mode = [number intValue];
1132 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1135 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1136 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1138 NSLog(@"operatorNameStyle= %@", style);
1139 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1140 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1144 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1146 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1147 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1150 // XXX: replace this with [SBStatusBarTimeView tile]
1151 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1152 id &_time(MSHookIvar<id>(self, "_time"));
1153 if (_time != nil && [_time class] != [WBTimeLabel class])
1154 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1155 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1158 @interface UIView (WinterBoard)
1159 - (bool) wb$isWBImageView;
1160 - (void) wb$logHierarchy;
1163 @implementation UIView (WinterBoard)
1165 - (bool) wb$isWBImageView {
1169 - (void) wb$logHierarchy {
1170 WBLogHierarchy(self);
1175 @interface WBImageView : UIImageView {
1178 - (bool) wb$isWBImageView;
1179 - (void) wb$updateFrame;
1182 @implementation WBImageView
1184 - (bool) wb$isWBImageView {
1188 - (void) wb$updateFrame {
1189 CGRect frame([self frame]);
1192 for (UIView *view(self); ; ) {
1193 view = [view superview];
1196 frame.origin.y -= [view frame].origin.y;
1199 [self setFrame:frame];
1204 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1205 NSArray *subviews([self subviews]);
1206 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1207 if (view != nil && [view wb$isWBImageView])
1208 [view wb$updateFrame];
1209 _SBIconList$setFrame$(self, sel, frame);
1212 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1213 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1214 NSArray *lists([_iconModel iconLists]);
1216 for (unsigned i(0), e([lists count]); i != e; ++i)
1217 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]])) {
1218 SBIconList *list([lists objectAtIndex:i]);
1219 NSArray *subviews([list subviews]);
1221 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1222 if (view == nil || ![view wb$isWBImageView]) {
1223 view = [[[WBImageView alloc] init] autorelease];
1224 [list insertSubview:view atIndex:0];
1227 UIImage *image([UIImage imageWithContentsOfFile:path]);
1229 CGRect frame([view frame]);
1230 frame.size = [image size];
1231 [view setFrame:frame];
1233 [view setImage:image];
1234 [view wb$updateFrame];
1237 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1240 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1241 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1243 [self setClipsToBounds:NO];
1247 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1248 id &_label(MSHookIvar<id>(self, "_label"));
1249 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1251 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1252 [_label setInDock:docked];
1253 return _SBIconLabel$setInDock$(self, sel, docked);
1256 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1257 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1260 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1261 _SBDockIconListView$setFrame$(self, sel, frame);
1264 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1265 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1266 NSString *identifier = [self bundleIdentifier];
1267 NSLocale *locale = [NSLocale currentLocale];
1268 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1270 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1271 NSString *file = table == nil ? @"Localizable" : table;
1272 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1273 NSDictionary *strings;
1274 if ((strings = [Strings_ objectForKey:name]) != nil) {
1275 if (static_cast<id>(strings) != [NSNull null]) strings:
1276 if (NSString *value = [strings objectForKey:key])
1278 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1281 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1282 [Strings_ setObject:[strings autorelease] forKey:name];
1286 [Strings_ setObject:[NSNull null] forKey:name];
1287 return MSOldCall(key, value, table);
1290 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1291 MSClassHook(WebCoreFrameBridge)
1293 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1296 void **core(reinterpret_cast<void **>([node _node]));
1297 if (core == NULL || core[6] == NULL)
1299 return MSOldCall(node, width);
1303 MSHook(void, SBIconLabel$drawRect$, SBIconLabel *self, SEL sel, CGRect rect) {
1304 CGRect bounds = [self bounds];
1306 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1309 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1310 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1312 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1314 NSString *style = [NSString stringWithFormat:@""
1315 "font-family: Helvetica; "
1316 "font-weight: bold; "
1318 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1319 ? @"font-size: 12px; "
1320 : @"font-size: 11px; "
1324 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1326 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1328 bool ellipsis(false);
1329 float max = 75, width;
1331 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
1334 size_t length([label length]);
1335 float spacing((width - max) / (length - 1));
1337 if (spacing > 1.25) {
1339 label = [label substringToIndex:(length - 1)];
1343 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
1347 label = [label stringByAppendingString:@"..."];
1349 if (NSString *custom = [Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")])
1350 style = [style stringByAppendingString:custom];
1352 CGSize size = [label sizeWithStyle:style forWidth:bounds.size.width];
1353 [label drawAtPoint:CGPointMake((bounds.size.width - size.width) / 2, 0) withStyle:style];
1357 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1359 [balloon setBackgroundColor:[UIColor clearColor]];
1362 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1363 if ((self = MSOldCall(style, reuse)) != nil) {
1364 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1368 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1369 if ((self = MSOldCall(style, reuse)) != nil) {
1370 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1371 [_label setBackgroundColor:[UIColor clearColor]];
1375 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1376 MSOldCall(UITableViewCellSeparatorStyleNone);
1379 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1380 if ((self = MSOldCall(frame, style)) != nil) {
1381 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1385 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1388 if (NSString *path = $getTheme$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil]))
1389 if (UIImage *image = [[UIImage alloc] initWithContentsOfFile:path]) {
1390 [image autorelease];
1392 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1393 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1395 if (&_transcriptTable != NULL)
1396 table = _transcriptTable;
1397 else if (&_transcriptLayer != NULL)
1398 table = _transcriptLayer;
1402 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1403 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1406 [placard insertSubview:background atIndex:0];
1408 [table setBackgroundColor:[UIColor clearColor]];
1409 [placard insertSubview:background belowSubview:table];
1415 // %hook _UIImageWithName() {{{
1416 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1418 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1425 if (_UIPackedImageTableGetIdentifierForName != NULL)
1426 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1427 else if (_UISharedImageNameGetIdentifier != NULL) {
1428 identifier = _UISharedImageNameGetIdentifier(name);
1429 packed = identifier != -1;
1436 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1439 return __UIImageWithName(name);
1441 NSNumber *key([NSNumber numberWithInt:identifier]);
1442 UIImage *image([UIImages_ objectForKey:key]);
1444 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1445 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true)) {
1446 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
1448 [image autorelease];
1450 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1451 return image == nil ? __UIImageWithName(name) : image;
1455 // %hook _UIImageWithNameInDomain() {{{
1456 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1457 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1458 UIImage *image([PathImages_ objectForKey:key]);
1460 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1462 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1463 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]], true)) {
1464 image = [[UIImage alloc] initWithContentsOfFile:path];
1466 [image autorelease];
1468 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1469 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1473 // %hook GSFontCreateWithName() {{{
1474 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1476 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1477 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1478 name = [font UTF8String];
1479 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1480 // size *= [scale floatValue];
1481 return _GSFontCreateWithName(name, traits, size);
1485 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1486 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1488 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1490 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1492 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1493 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1495 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1498 NSString *path = [NSString stringWithUTF8String:a1];
1499 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1500 NSString *file = [path substringFromIndex:31];
1501 for (NSString *theme in Themes_) {
1502 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1503 if ([Manager_ fileExistsAtPath:path]) {
1504 strcpy(a1, [path UTF8String]);
1513 static void ChangeWallpaper(
1514 CFNotificationCenterRef center,
1518 CFDictionaryRef info
1521 NSLog(@"WB:Debug:ChangeWallpaper!");
1524 if (WallpaperFile_ != nil) {
1525 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1527 image = [image autorelease];
1530 if (WallpaperImage_ != nil)
1531 [WallpaperImage_ setImage:image];
1532 if (WallpaperPage_ != nil)
1533 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1537 #define WBRename(name, sel, imp) \
1538 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
1540 template <typename Type_>
1541 static void msset(Type_ &function, MSImageRef image, const char *name) {
1542 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1545 template <typename Type_>
1546 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1547 struct nlist &name(nl[index]);
1548 uintptr_t value(name.n_value);
1549 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1550 value |= 0x00000001;
1551 function = reinterpret_cast<Type_>(value);
1554 template <typename Type_>
1555 static void dlset(Type_ &function, const char *name) {
1556 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1559 // %hook CGImageReadCreateWithFile() {{{
1560 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1562 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1563 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1564 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1570 static void SBInitialize() {
1571 _UIImage$defaultDesktopImage = MSHookMessage(object_getClass($UIImage), @selector(defaultDesktopImage), &$UIImage$defaultDesktopImage);
1573 bool olden(dlsym(RTLD_DEFAULT, "GSLibraryCopyGenerationInfoValueForKey") == NULL);
1576 WBRename(SBApplication, pathForIcon, pathForIcon);
1577 WBRename(SBApplicationIcon, icon, icon);
1578 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1581 WBRename(SBBookmarkIcon, icon, icon);
1582 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1583 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1584 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1585 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
1587 WBRename(SBWidgetApplicationIcon, icon, icon);
1589 WBRename(SBDockIconListView, setFrame:, setFrame$);
1590 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
1593 WBRename(SBIconLabel, drawRect:, drawRect$);
1595 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
1596 WBRename(SBIconLabel, setInDock:, setInDock$);
1598 WBRename(SBIconList, setFrame:, setFrame$);
1600 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
1601 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
1602 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
1603 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
1605 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
1606 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
1607 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
1609 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
1611 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
1612 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
1613 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
1614 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
1615 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
1616 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
1617 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
1618 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
1619 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
1622 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
1626 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1628 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
1629 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
1631 Manager_ = [[NSFileManager defaultManager] retain];
1632 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
1634 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
1636 // Load Settings.plist {{{
1637 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
1638 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
1639 SummerBoard_ = [value boolValue];
1640 if (NSNumber *value = [settings objectForKey:@"Debug"])
1641 Debug_ = [value boolValue];
1643 NSArray *themes([settings objectForKey:@"Themes"]);
1645 if (NSString *theme = [settings objectForKey:@"Theme"])
1646 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
1648 [NSNumber numberWithBool:true], @"Active",
1652 for (NSDictionary *theme in themes) {
1653 NSNumber *active([theme objectForKey:@"Active"]);
1654 if (![active boolValue])
1657 NSString *name([theme objectForKey:@"Name"]);
1661 NSString *theme(nil);
1663 #define testForTheme(format...) \
1664 if (theme == nil) { \
1665 NSString *path = [NSString stringWithFormat:format]; \
1666 if ([Manager_ fileExistsAtPath:path]) { \
1667 [Themes_ addObject:path]; \
1672 testForTheme(@"/Library/Themes/%@.theme", name)
1673 testForTheme(@"/Library/Themes/%@", name)
1674 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
1679 // Merge Info.plist {{{
1680 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1682 for (NSString *theme in Themes_)
1683 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
1684 for (NSString *key in [info allKeys])
1685 if ([Info_ objectForKey:key] == nil)
1686 [Info_ setObject:[info objectForKey:key] forKey:key];
1690 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
1691 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
1692 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
1695 // GraphicsServices {{{
1697 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
1701 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
1702 void *(*CGImageReadCreateWithFile)(NSString *, int);
1703 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
1704 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
1709 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
1710 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]);
1712 CFNotificationCenterAddObserver(
1713 CFNotificationCenterGetDarwinNotifyCenter(),
1714 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
1717 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
1718 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
1719 if (MediaPlayer != nil)
1722 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
1723 $MPVideoView = objc_getClass("MPVideoView");
1730 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
1732 memset(nl, 0, sizeof(nl));
1733 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
1734 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
1735 nl[2].n_un.n_name = (char *) "__UIKitBundle";
1736 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
1737 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
1740 nlset(_UIApplicationImageWithName, nl, 0);
1741 nlset(_UIImageWithNameInDomain, nl, 1);
1742 nlset(_UIKitBundle, nl, 2);
1743 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
1744 nlset(_UISharedImageNameGetIdentifier, nl, 4);
1746 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
1747 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
1748 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);