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 path = [NSString stringWithFormat:@"%@/%@", theme, file];
250 if ([Manager_ fileExistsAtPath:path])
257 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:files];
261 // $pathForFile$inBundle$() {{{
262 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool ui) {
263 NSString *identifier = [bundle bundleIdentifier];
264 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
266 if (identifier != nil)
267 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
268 if (NSString *folder = [[bundle bundlePath] lastPathComponent])
269 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
271 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
273 #define remapResourceName(oldname, newname) \
274 else if ([file isEqualToString:(oldname)]) \
275 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
277 bool summer(SpringBoard_ && SummerBoard_);
279 if (identifier == nil);
280 else if ([identifier isEqualToString:@"com.apple.chatkit"])
281 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
282 else if ([identifier isEqualToString:@"com.apple.calculator"])
283 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
285 remapResourceName(@"FSO_BG.png", @"StatusBar")
286 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
287 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
289 if (NSString *path = $getTheme$(names, ui))
296 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
297 NSString *identifier = [self bundleIdentifier];
298 NSString *path = [self path];
299 NSString *folder = [path lastPathComponent];
300 NSString *dname = [self displayName];
301 NSString *didentifier = [self displayIdentifier];
304 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
306 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
308 /* XXX: I might need to keep this for backwards compatibility
309 if (identifier != nil)
310 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
312 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
314 #define testForIcon(Name) \
315 if (NSString *name = Name) \
316 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
318 if (![didentifier isEqualToString:identifier])
319 testForIcon(didentifier);
321 testForIcon(identifier);
324 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
327 if (didentifier != nil) {
328 testForIcon([English_ objectForKey:didentifier]);
330 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
331 if ([parts count] != 1)
332 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
333 testForIcon([english objectForKey:[parts lastObject]]);
336 if (NSString *path = $getTheme$(names))
342 // -[NSBundle wb$bundleWithFile] {{{
343 @interface NSBundle (WinterBoard)
344 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
347 @implementation NSBundle (WinterBoard)
349 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
350 path = [path stringByDeletingLastPathComponent];
351 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
354 NSBundle *bundle([Bundles_ objectForKey:path]);
355 if (reinterpret_cast<id>(bundle) == [NSNull null])
357 else if (bundle == nil) {
358 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
359 bundle = [NSBundle bundleWithPath:path];
361 bundle = [NSBundle wb$bundleWithFile:path];
363 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
364 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
372 // -[NSString wb$themedPath] {{{
373 @interface NSString (WinterBoard)
374 - (NSString *) wb$themedPath;
377 @implementation NSString (WinterBoard)
379 - (NSString *) wb$themedPath {
381 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
383 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
384 NSString *file([self stringByResolvingSymlinksInPath]);
385 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
386 if ([file hasPrefix:prefix]) {
387 NSUInteger length([prefix length]);
388 if (length != [file length])
389 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
400 void WBLogRect(const char *tag, struct CGRect rect) {
401 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
404 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
405 CGRect frame([view frame]);
406 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]);
408 for (UIView *child in [view subviews])
409 WBLogHierarchy(child, index++, indent + 1);
412 UIImage *$cacheForImage$(UIImage *image) {
413 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
414 CGRect rect = {CGPointMake(1, 1), [image size]};
415 CGSize size = {rect.size.width + 2, rect.size.height + 2};
417 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
418 CGColorSpaceRelease(space);
420 CGContextDrawImage(context, rect, [image CGImage]);
421 CGImageRef ref(CGBitmapContextCreateImage(context));
422 CGContextRelease(context);
424 UIImage *cache([UIImage imageWithCGImage:ref]);
430 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
431 //if ([name isEqualToString:@"icons"]) return nil;
432 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
435 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
436 NSString *key([icon displayIdentifier]);
438 if (UIImage *image = [icon icon]) {
439 CGSize size = [image size];
440 if (size.width != 59 || size.height != 60) {
441 UIImage *cache($cacheForImage$(image));
442 [Cache_ setObject:cache forKey:key];
447 _SBIconModel$cacheImageForIcon$(self, sel, icon);
450 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
451 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
452 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
454 NSString *key([icon displayIdentifier]);
456 if (UIImage *image = [icon icon]) {
457 CGSize size = [image size];
458 if (size.width != 59 || size.height != 60) {
459 UIImage *cache($cacheForImage$(image));
460 [Cache_ setObject:cache forKey:key];
466 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
467 NSString *key([icon displayIdentifier]);
468 if (UIImage *image = [Cache_ objectForKey:key])
471 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
474 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
476 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
477 NSString *key([icon displayIdentifier]);
478 if (UIImage *image = [Cache_ objectForKey:key])
481 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
484 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
485 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
486 [self setBackgroundColor:[UIColor clearColor]];
487 for (UIView *child in [self subviews])
488 [child setBackgroundColor:[UIColor clearColor]];
492 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
493 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
494 [self setBackgroundColor:[UIColor clearColor]];
498 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
499 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
500 float inset([self edgeInset]);
501 [[UIColor clearColor] set];
502 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
503 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
506 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
507 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
508 if (NSString *path = $pathForIcon$([self application]))
509 return [UIImage imageWithContentsOfFile:path];
510 return _SBApplicationIcon$icon(self, sel);
513 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
515 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
516 if (IsWild_ && false) // XXX: delete this code, it should not be supported
517 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
518 return [UIImage imageWithContentsOfFile:path72];
519 if (NSString *path = $pathForIcon$([self application]))
520 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
522 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
523 width = [$SBIcon defaultIconImageSize].width;
526 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
529 return _SBApplicationIcon$generateIconImage$(self, sel, type);
532 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
534 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
535 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
536 return [UIImage imageWithContentsOfFile:path];
537 return _SBWidgetApplicationIcon$icon(self, sel);
540 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
542 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
543 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
544 return [UIImage imageWithContentsOfFile:path];
545 return _SBBookmarkIcon$icon(self, sel);
548 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
549 if (NSString *path = $pathForIcon$(self))
551 return _SBApplication$pathForIcon(self, sel);
554 static UIImage *CachedImageAtPath(NSString *path) {
555 path = [path stringByResolvingSymlinksInPath];
556 UIImage *image = [PathImages_ objectForKey:path];
558 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
559 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
561 image = [image autorelease];
562 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
566 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
567 NSBundle *bundle = [NSBundle mainBundle];
569 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
570 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
571 return CachedImageAtPath(path);
572 return __UIApplicationImageWithName(name);
575 #define WBDelegate(delegate) \
576 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
578 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
579 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
581 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
585 - (void) forwardInvocation:(NSInvocation*)inv { \
586 SEL sel = [inv selector]; \
587 if ([delegate respondsToSelector:sel]) \
588 [inv invokeWithTarget:delegate]; \
590 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
593 // %hook -[NSBundle pathForResource:ofType:] {{{
594 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
595 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
597 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
598 if (NSString *path = $pathForFile$inBundle$(file, self, false))
600 return MSOldCall(resource, type);
604 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
605 NSBundle *bundle([NSBundle mainBundle]);
607 CFLocaleRef locale(CFLocaleCopyCurrent());
608 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
611 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
613 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
614 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
615 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
616 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
620 CFRelease(formatter);
622 NSString *datestyle([@""
623 "font-family: Helvetica; "
624 "font-weight: bold; "
627 "" stringByAppendingString:(IsWild_
628 ? @"font-size: 54px; "
629 : @"font-size: 39px; "
632 NSString *daystyle([@""
633 "font-family: Helvetica; "
634 "font-weight: bold; "
636 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
637 "" stringByAppendingString:(IsWild_
638 ? @"font-size: 11px; "
639 : @"font-size: 9px; "
642 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
643 datestyle = [datestyle stringByAppendingString:style];
644 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
645 daystyle = [daystyle stringByAppendingString:style];
647 float width([self bounds].size.width);
649 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
650 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
652 unsigned base0(IsWild_ ? 89 : 70);
653 if ($GSFontGetUseLegacyFontMetrics())
655 unsigned base1(IsWild_ ? 18 : 16);
662 [(NSString *)date drawAtPoint:CGPointMake(
663 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
664 ) withStyle:datestyle];
666 [(NSString *)day drawAtPoint:CGPointMake(
667 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
668 ) withStyle:daystyle];
674 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
675 void $setBarStyle$_(NSString *name, int &style) {
677 NSLog(@"WB:Debug:%@Style:%d", name, style);
678 NSNumber *number = nil;
680 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
682 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
684 style = [number intValue];
686 NSLog(@"WB:Debug:%@Style=%d", name, style);
690 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
691 $setBarStyle$_(@"Toolbar", style);
692 return MSOldCall(style);
695 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
696 $setBarStyle$_(@"NavigationBar", style);
697 return MSOldCall(style);
701 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
702 [[self superview] setBackgroundColor:[UIColor clearColor]];
703 _SBButtonBar$didMoveToSuperview(self, sel);
706 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
707 [[self superview] setBackgroundColor:[UIColor clearColor]];
708 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
711 MSHook(UIImage *, UIImage$defaultDesktopImage, UIImage *self, SEL sel) {
713 NSLog(@"WB:Debug:DefaultDesktopImage");
714 if (NSString *path = $getTheme$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil]))
715 return [UIImage imageWithContentsOfFile:path];
716 return _UIImage$defaultDesktopImage(self, sel);
719 static NSArray *Wallpapers_;
720 static bool Papered_;
722 static NSString *WallpaperFile_;
723 static UIImageView *WallpaperImage_;
724 static UIWebDocumentView *WallpaperPage_;
725 static NSURL *WallpaperURL_;
727 #define _release(object) \
728 do if (object != nil) { \
733 static UIImage *$getImage$(NSString *path) {
734 UIImage *image([UIImage imageWithContentsOfFile:path]);
736 unsigned scale($getScale$(path));
737 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
738 [image setScale:scale];
743 // %hook -[SBUIController init] {{{
744 MSInstanceMessageHook0(id, SBUIController, init) {
749 NSString *paper($getTheme$(Wallpapers_, true));
753 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
754 char *machine = new char[size];
756 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
757 perror("sysctlbyname(\"hw.machine\", ?)");
762 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
765 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
767 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
768 [Info_ setObject:[NSNumber numberWithBool:(
769 !(paper != nil || GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"))) ||
770 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
771 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
772 )] forKey:@"UndockedIconLabels"];
775 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
778 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
779 if (&_wallpaperView != NULL) {
780 [_wallpaperView removeFromSuperview];
781 [_wallpaperView release];
782 _wallpaperView = nil;
786 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
787 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
790 if (&_contentLayer != NULL)
791 player = &_contentLayer;
792 else if (&_contentView != NULL)
793 player = &_contentView;
796 UIView *layer(player == NULL ? nil : *player);
798 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
799 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
800 [window setContentView:content];
802 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
803 [window setBackgroundColor:[_window backgroundColor]];
804 [_window setBackgroundColor:[UIColor clearColor]];
806 [window setLevel:-1000];
807 [window setHidden:NO];
809 /*if (player != NULL)
812 [content setBackgroundColor:[layer backgroundColor]];
813 [layer setBackgroundColor:[UIColor clearColor]];
816 if (!SummerBoard_ || !IsWild_)
819 CGRect bounds([content bounds]);
820 bounds.origin.y = -30;
821 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
822 [content addSubview:indirect];
823 [indirect zoomToScale:2.4];
826 _release(WallpaperFile_);
827 _release(WallpaperImage_);
828 _release(WallpaperPage_);
829 _release(WallpaperURL_);
831 if (NSString *path = paper) {
832 if ([path hasSuffix:@".mp4"]) {
836 static AVController *controller_(nil);
837 if (controller_ == nil) {
838 AVQueue *queue([AVQueue avQueue]);
839 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
842 AVQueue *queue([controller_ queue]);
844 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
845 [controller_ setLayer:[video _layer]];
847 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
848 [queue appendItem:item error:&error];
850 [controller_ play:&error];
851 #elif UseMPMoviePlayerController
852 NSURL *url([NSURL fileURLWithPath:path]);
853 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
854 controller.movieControlMode = MPMovieControlModeHidden;
857 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
858 [video setMovieWithPath:path];
859 [video setRepeatMode:1];
860 [video setRepeatGap:-1];
861 [video playFromBeginning];;
864 [indirect addSubview:video];
867 if ([path hasSuffix:@".png"] || [path hasSuffix:@".jpg"]) {
868 if (UIImage *image = $getImage$(path)) {
869 WallpaperFile_ = [path retain];
870 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
871 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
872 [WallpaperImage_ setAlpha:[number floatValue]];
873 [indirect addSubview:WallpaperImage_];
877 if ([path hasSuffix:@".html"]) {
878 CGRect bounds = [indirect bounds];
880 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
881 [view setAutoresizes:true];
883 WallpaperPage_ = [view retain];
884 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
886 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
888 [view setBackgroundColor:[UIColor clearColor]];
889 if ([view respondsToSelector:@selector(setDrawsBackground:)])
890 [view setDrawsBackground:NO];
891 [[view webView] setDrawsBackground:NO];
893 [indirect addSubview:view];
897 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
898 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
899 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
900 if ([Manager_ fileExistsAtPath:html]) {
901 CGRect bounds = [indirect bounds];
903 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
904 [view setAutoresizes:true];
906 NSURL *url = [NSURL fileURLWithPath:html];
907 [view loadRequest:[NSURLRequest requestWithURL:url]];
909 [view setBackgroundColor:[UIColor clearColor]];
910 if ([view respondsToSelector:@selector(setDrawsBackground:)])
911 [view setDrawsBackground:NO];
912 [[view webView] setDrawsBackground:NO];
914 [indirect addSubview:view];
922 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
923 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
924 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
926 if (path != nil && _backgroundView != nil)
929 _SBAwayView$updateDesktopImage$(self, sel, image);
932 CGRect bounds = [self bounds];
934 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
935 [view setAutoresizes:true];
937 if (WallpaperPage_ != nil)
938 [WallpaperPage_ release];
939 WallpaperPage_ = [view retain];
941 if (WallpaperURL_ != nil)
942 [WallpaperURL_ release];
943 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
945 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
947 [[view webView] setDrawsBackground:false];
948 [view setBackgroundColor:[UIColor clearColor]];
950 [self insertSubview:view aboveSubview:_backgroundView];
954 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
955 extern "C" CGColorRef CGGStateGetFillColor(void *);
956 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
957 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
959 /* WBTimeLabel {{{ */
960 @interface WBTimeLabel : NSProxy {
962 _transient SBStatusBarTimeView *view_;
965 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
969 @implementation WBTimeLabel
976 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
977 time_ = [time retain];
982 - (NSString *) description {
988 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
989 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
990 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
992 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
993 "font-family: Helvetica; "
994 "font-weight: bold; "
997 "%@", _mode ? @"white" : @"black", custom]];
1002 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1007 /* WBBadgeLabel {{{ */
1008 @interface WBBadgeLabel : NSProxy {
1012 - (id) initWithBadge:(NSString *)badge;
1013 - (NSString *) description;
1017 @implementation WBBadgeLabel
1024 - (id) initWithBadge:(NSString *)badge {
1025 badge_ = [badge retain];
1029 - (NSString *) description {
1030 return [badge_ description];
1035 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1036 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1037 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1038 "font-family: Helvetica; "
1039 "font-weight: bold; "
1047 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1054 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1055 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1056 alpha = [number floatValue];
1057 return MSOldCall(alpha);
1060 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1061 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1062 alpha = [number floatValue];
1063 return MSOldCall(alpha);
1066 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1067 if ((self = MSOldCall()) != nil) {
1068 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1069 // XXX: note: this is overridden above, which is silly
1070 float alpha([number floatValue]);
1071 [self setIconImageAlpha:alpha];
1072 [self setIconLabelAlpha:alpha];
1077 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1078 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1079 alpha = [number floatValue];
1080 return MSOldCall(alpha);
1084 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1085 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1086 id &_badge(MSHookIvar<id>(self, "_badge"));
1088 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1093 void SBStatusBarController$setStatusBarMode(int &mode) {
1095 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1096 if (mode < 100) // 104:hidden 105:glowing
1097 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1098 mode = [number intValue];
1101 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1102 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1103 SBStatusBarController$setStatusBarMode(mode);
1104 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1107 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1108 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1109 SBStatusBarController$setStatusBarMode(mode);
1110 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1113 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) {
1114 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1115 SBStatusBarController$setStatusBarMode(mode);
1116 //NSLog(@"mode=%u", mode);
1117 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1120 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1121 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1122 mode = [number intValue];
1123 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1126 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1127 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1129 NSLog(@"operatorNameStyle= %@", style);
1130 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1131 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1135 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1137 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1138 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1141 // XXX: replace this with [SBStatusBarTimeView tile]
1142 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1143 id &_time(MSHookIvar<id>(self, "_time"));
1144 if (_time != nil && [_time class] != [WBTimeLabel class])
1145 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1146 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1149 @interface UIView (WinterBoard)
1150 - (bool) wb$isWBImageView;
1151 - (void) wb$logHierarchy;
1154 @implementation UIView (WinterBoard)
1156 - (bool) wb$isWBImageView {
1160 - (void) wb$logHierarchy {
1161 WBLogHierarchy(self);
1166 @interface WBImageView : UIImageView {
1169 - (bool) wb$isWBImageView;
1170 - (void) wb$updateFrame;
1173 @implementation WBImageView
1175 - (bool) wb$isWBImageView {
1179 - (void) wb$updateFrame {
1180 CGRect frame([self frame]);
1183 for (UIView *view(self); ; ) {
1184 view = [view superview];
1187 frame.origin.y -= [view frame].origin.y;
1190 [self setFrame:frame];
1195 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1196 NSArray *subviews([self subviews]);
1197 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1198 if (view != nil && [view wb$isWBImageView])
1199 [view wb$updateFrame];
1200 _SBIconList$setFrame$(self, sel, frame);
1203 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1204 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1205 NSArray *lists([_iconModel iconLists]);
1207 for (unsigned i(0), e([lists count]); i != e; ++i)
1208 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]])) {
1209 SBIconList *list([lists objectAtIndex:i]);
1210 NSArray *subviews([list subviews]);
1212 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1213 if (view == nil || ![view wb$isWBImageView]) {
1214 view = [[[WBImageView alloc] init] autorelease];
1215 [list insertSubview:view atIndex:0];
1218 UIImage *image([UIImage imageWithContentsOfFile:path]);
1220 CGRect frame([view frame]);
1221 frame.size = [image size];
1222 [view setFrame:frame];
1224 [view setImage:image];
1225 [view wb$updateFrame];
1228 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1231 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1232 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1234 [self setClipsToBounds:NO];
1238 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1239 id &_label(MSHookIvar<id>(self, "_label"));
1240 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1242 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1243 [_label setInDock:docked];
1244 return _SBIconLabel$setInDock$(self, sel, docked);
1247 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1248 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1251 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1252 _SBDockIconListView$setFrame$(self, sel, frame);
1255 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1256 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1257 NSString *identifier = [self bundleIdentifier];
1258 NSLocale *locale = [NSLocale currentLocale];
1259 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1261 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1262 NSString *file = table == nil ? @"Localizable" : table;
1263 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1264 NSDictionary *strings;
1265 if ((strings = [Strings_ objectForKey:name]) != nil) {
1266 if (static_cast<id>(strings) != [NSNull null]) strings:
1267 if (NSString *value = [strings objectForKey:key])
1269 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1272 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1273 [Strings_ setObject:[strings autorelease] forKey:name];
1277 [Strings_ setObject:[NSNull null] forKey:name];
1278 return MSOldCall(key, value, table);
1281 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1282 MSClassHook(WebCoreFrameBridge)
1284 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1287 void **core(reinterpret_cast<void **>([node _node]));
1288 if (core == NULL || core[6] == NULL)
1290 return MSOldCall(node, width);
1294 MSHook(void, SBIconLabel$drawRect$, SBIconLabel *self, SEL sel, CGRect rect) {
1295 CGRect bounds = [self bounds];
1297 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1300 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1301 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1303 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1305 NSString *style = [NSString stringWithFormat:@""
1306 "font-family: Helvetica; "
1307 "font-weight: bold; "
1309 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1310 ? @"font-size: 12px; "
1311 : @"font-size: 11px; "
1315 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1317 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1319 bool ellipsis(false);
1320 float max = 75, width;
1322 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
1325 size_t length([label length]);
1326 float spacing((width - max) / (length - 1));
1328 if (spacing > 1.25) {
1330 label = [label substringToIndex:(length - 1)];
1334 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
1338 label = [label stringByAppendingString:@"..."];
1340 if (NSString *custom = [Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")])
1341 style = [style stringByAppendingString:custom];
1343 CGSize size = [label sizeWithStyle:style forWidth:bounds.size.width];
1344 [label drawAtPoint:CGPointMake((bounds.size.width - size.width) / 2, 0) withStyle:style];
1348 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1350 [balloon setBackgroundColor:[UIColor clearColor]];
1353 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1354 if ((self = MSOldCall(style, reuse)) != nil) {
1355 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1359 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1360 if ((self = MSOldCall(style, reuse)) != nil) {
1361 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1362 [_label setBackgroundColor:[UIColor clearColor]];
1366 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1367 MSOldCall(UITableViewCellSeparatorStyleNone);
1370 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1371 if ((self = MSOldCall(frame, style)) != nil) {
1372 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1376 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1379 if (NSString *path = $getTheme$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil]))
1380 if (UIImage *image = [[UIImage alloc] initWithContentsOfFile:path]) {
1381 [image autorelease];
1383 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1384 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1386 if (&_transcriptTable != NULL)
1387 table = _transcriptTable;
1388 else if (&_transcriptLayer != NULL)
1389 table = _transcriptLayer;
1393 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1394 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1397 [placard insertSubview:background atIndex:0];
1399 [table setBackgroundColor:[UIColor clearColor]];
1400 [placard insertSubview:background belowSubview:table];
1406 // %hook _UIImageWithName() {{{
1407 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1409 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1416 if (_UIPackedImageTableGetIdentifierForName != NULL)
1417 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1418 else if (_UISharedImageNameGetIdentifier != NULL) {
1419 identifier = _UISharedImageNameGetIdentifier(name);
1420 packed = identifier != -1;
1427 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1430 return __UIImageWithName(name);
1432 NSNumber *key([NSNumber numberWithInt:identifier]);
1433 UIImage *image([UIImages_ objectForKey:key]);
1435 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1436 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true)) {
1437 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
1439 [image autorelease];
1441 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1442 return image == nil ? __UIImageWithName(name) : image;
1446 // %hook _UIImageWithNameInDomain() {{{
1447 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1448 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1449 UIImage *image([PathImages_ objectForKey:key]);
1451 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1453 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1454 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]], true)) {
1455 image = [[UIImage alloc] initWithContentsOfFile:path];
1457 [image autorelease];
1459 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1460 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1464 // %hook GSFontCreateWithName() {{{
1465 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1467 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1468 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1469 name = [font UTF8String];
1470 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1471 // size *= [scale floatValue];
1472 return _GSFontCreateWithName(name, traits, size);
1476 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1477 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1479 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1481 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1483 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1484 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1486 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1489 NSString *path = [NSString stringWithUTF8String:a1];
1490 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1491 NSString *file = [path substringFromIndex:31];
1492 for (NSString *theme in Themes_) {
1493 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1494 if ([Manager_ fileExistsAtPath:path]) {
1495 strcpy(a1, [path UTF8String]);
1504 static void ChangeWallpaper(
1505 CFNotificationCenterRef center,
1509 CFDictionaryRef info
1512 NSLog(@"WB:Debug:ChangeWallpaper!");
1515 if (WallpaperFile_ != nil) {
1516 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1518 image = [image autorelease];
1521 if (WallpaperImage_ != nil)
1522 [WallpaperImage_ setImage:image];
1523 if (WallpaperPage_ != nil)
1524 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1528 #define WBRename(name, sel, imp) \
1529 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
1531 template <typename Type_>
1532 static void msset(Type_ &function, MSImageRef image, const char *name) {
1533 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1536 template <typename Type_>
1537 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1538 struct nlist &name(nl[index]);
1539 uintptr_t value(name.n_value);
1540 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1541 value |= 0x00000001;
1542 function = reinterpret_cast<Type_>(value);
1545 template <typename Type_>
1546 static void dlset(Type_ &function, const char *name) {
1547 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1550 // %hook CGImageReadCreateWithFile() {{{
1551 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1553 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1554 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1555 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1561 static void SBInitialize() {
1562 _UIImage$defaultDesktopImage = MSHookMessage(object_getClass($UIImage), @selector(defaultDesktopImage), &$UIImage$defaultDesktopImage);
1564 bool olden(dlsym(RTLD_DEFAULT, "GSLibraryCopyGenerationInfoValueForKey") == NULL);
1567 WBRename(SBApplication, pathForIcon, pathForIcon);
1568 WBRename(SBApplicationIcon, icon, icon);
1569 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1572 WBRename(SBBookmarkIcon, icon, icon);
1573 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1574 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1575 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1576 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
1578 WBRename(SBWidgetApplicationIcon, icon, icon);
1580 WBRename(SBDockIconListView, setFrame:, setFrame$);
1581 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
1584 WBRename(SBIconLabel, drawRect:, drawRect$);
1586 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
1587 WBRename(SBIconLabel, setInDock:, setInDock$);
1589 WBRename(SBIconList, setFrame:, setFrame$);
1591 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
1592 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
1593 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
1594 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
1596 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
1597 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
1598 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
1600 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
1602 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
1603 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
1604 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
1605 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
1606 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
1607 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
1608 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
1609 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
1610 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
1613 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
1617 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1619 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
1620 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
1622 Manager_ = [[NSFileManager defaultManager] retain];
1623 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
1625 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
1627 // Load Settings.plist {{{
1628 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
1629 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
1630 SummerBoard_ = [value boolValue];
1631 if (NSNumber *value = [settings objectForKey:@"Debug"])
1632 Debug_ = [value boolValue];
1634 NSArray *themes([settings objectForKey:@"Themes"]);
1636 if (NSString *theme = [settings objectForKey:@"Theme"])
1637 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
1639 [NSNumber numberWithBool:true], @"Active",
1643 for (NSDictionary *theme in themes) {
1644 NSNumber *active([theme objectForKey:@"Active"]);
1645 if (![active boolValue])
1648 NSString *name([theme objectForKey:@"Name"]);
1652 NSString *theme(nil);
1654 #define testForTheme(format...) \
1655 if (theme == nil) { \
1656 NSString *path = [NSString stringWithFormat:format]; \
1657 if ([Manager_ fileExistsAtPath:path]) { \
1658 [Themes_ addObject:path]; \
1663 testForTheme(@"/Library/Themes/%@.theme", name)
1664 testForTheme(@"/Library/Themes/%@", name)
1665 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
1670 // Merge Info.plist {{{
1671 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1673 for (NSString *theme in Themes_)
1674 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
1675 for (NSString *key in [info allKeys])
1676 if ([Info_ objectForKey:key] == nil)
1677 [Info_ setObject:[info objectForKey:key] forKey:key];
1681 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
1682 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
1683 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
1686 // GraphicsServices {{{
1688 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
1692 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
1693 void *(*CGImageReadCreateWithFile)(NSString *, int);
1694 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
1695 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
1700 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
1701 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]);
1703 CFNotificationCenterAddObserver(
1704 CFNotificationCenterGetDarwinNotifyCenter(),
1705 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
1708 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
1709 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
1710 if (MediaPlayer != nil)
1713 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
1714 $MPVideoView = objc_getClass("MPVideoView");
1721 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
1723 memset(nl, 0, sizeof(nl));
1724 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
1725 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
1726 nl[2].n_un.n_name = (char *) "__UIKitBundle";
1727 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
1728 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
1731 nlset(_UIApplicationImageWithName, nl, 0);
1732 nlset(_UIImageWithNameInDomain, nl, 1);
1733 nlset(_UIKitBundle, nl, 2);
1734 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
1735 nlset(_UISharedImageNameGetIdentifier, nl, 4);
1737 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
1738 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
1739 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);