1 /* WinterBoard - Theme Manager for the iPhone
2 * Copyright (C) 2008-2011 Jay Freeman (saurik)
6 * Redistribution and use in source and binary
7 * forms, with or without modification, are permitted
8 * provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the
11 * above copyright notice, this list of conditions
12 * and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the
14 * above copyright notice, this list of conditions
15 * and the following disclaimer in the documentation
16 * and/or other materials provided with the
18 * 3. The name of the author may not be used to endorse
19 * or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
33 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 #define _trace() do { \
44 struct timeval _ctv; \
45 gettimeofday(&_ctv, NULL); \
50 NSLog(@"%lu.%.6u[%f]:_trace()@%s:%u[%s]\n", \
51 _ctv.tv_sec, _ctv.tv_usec, \
52 (_ctv.tv_sec - _ltv.tv_sec) + (_ctv.tv_usec - _ltv.tv_usec) / 1000000.0, \
53 __FILE__, __LINE__, __FUNCTION__\
60 #import <CoreFoundation/CoreFoundation.h>
61 #import <Foundation/Foundation.h>
62 #import <CoreGraphics/CoreGraphics.h>
63 #import <ImageIO/CGImageSource.h>
65 #import <Celestial/AVController.h>
66 #import <Celestial/AVItem.h>
67 #import <Celestial/AVQueue.h>
69 #include <substrate.h>
71 #import <UIKit/UIKit.h>
73 #import <SpringBoard/SBApplication.h>
74 #import <SpringBoard/SBApplicationIcon.h>
75 #import <SpringBoard/SBAppWindow.h>
76 #import <SpringBoard/SBAwayView.h>
77 #import <SpringBoard/SBBookmarkIcon.h>
78 #import <SpringBoard/SBButtonBar.h>
79 #import <SpringBoard/SBCalendarIconContentsView.h>
80 #import <SpringBoard/SBIconController.h>
81 #import <SpringBoard/SBIconLabel.h>
82 #import <SpringBoard/SBIconList.h>
83 #import <SpringBoard/SBIconModel.h>
84 #import <SpringBoard/SBImageCache.h>
85 // XXX: #import <SpringBoard/SBSearchView.h>
86 #import <SpringBoard/SBSearchTableViewCell.h>
87 #import <SpringBoard/SBStatusBarContentsView.h>
88 #import <SpringBoard/SBStatusBarController.h>
89 #import <SpringBoard/SBStatusBarOperatorNameView.h>
90 #import <SpringBoard/SBStatusBarTimeView.h>
91 #import <SpringBoard/SBUIController.h>
92 #import <SpringBoard/SBWidgetApplicationIcon.h>
94 #import <MobileSMS/mSMSMessageTranscriptController.h>
96 #import <MediaPlayer/MPMoviePlayerController.h>
97 #import <MediaPlayer/MPVideoView.h>
98 #import <MediaPlayer/MPVideoView-PlaybackControl.h>
100 #import <CoreGraphics/CGGeometry.h>
102 #import <ChatKit/CKMessageCell.h>
104 #include <sys/sysctl.h>
106 #include "WBMarkup.h"
108 extern "C" void __clear_cache (char *beg, char *end);
110 @protocol WinterBoard
114 Class $MPMoviePlayerController;
117 MSClassHook(NSBundle)
118 MSClassHook(NSString)
121 MSClassHook(UINavigationBar)
122 MSClassHook(UIToolbar)
124 MSClassHook(CKMessageCell)
125 MSClassHook(CKTimestampView)
126 MSClassHook(CKTranscriptController)
127 MSClassHook(CKTranscriptTableView)
129 MSClassHook(SBApplication)
130 MSClassHook(SBApplicationIcon)
131 MSClassHook(SBAwayView)
132 MSClassHook(SBBookmarkIcon)
133 MSClassHook(SBButtonBar)
134 MSClassHook(SBCalendarIconContentsView)
135 MSClassHook(SBDockIconListView)
137 MSClassHook(SBIconBadge)
138 MSClassHook(SBIconController)
139 MSClassHook(SBIconLabel)
140 MSClassHook(SBIconList)
141 MSClassHook(SBIconModel)
142 //MSClassHook(SBImageCache)
143 MSClassHook(SBSearchView)
144 MSClassHook(SBSearchTableViewCell)
145 MSClassHook(SBStatusBarContentsView)
146 MSClassHook(SBStatusBarController)
147 MSClassHook(SBStatusBarOperatorNameView)
148 MSClassHook(SBStatusBarTimeView)
149 MSClassHook(SBUIController)
150 MSClassHook(SBWidgetApplicationIcon)
152 __attribute__((__constructor__))
153 static void MSFixClass() {
155 $SBIcon = objc_getClass("SBIconView");
156 if ($CKTranscriptController == nil)
157 $CKTranscriptController = objc_getClass("mSMSMessageTranscriptController");
161 static bool Four_($SBDockIconListView != nil);
163 @interface NSDictionary (WinterBoard)
164 - (UIColor *) wb$colorForKey:(NSString *)key;
165 - (BOOL) wb$boolForKey:(NSString *)key;
168 @implementation NSDictionary (WinterBoard)
170 - (UIColor *) wb$colorForKey:(NSString *)key {
171 NSString *value = [self objectForKey:key];
178 - (BOOL) wb$boolForKey:(NSString *)key {
179 if (NSString *value = [self objectForKey:key])
180 return [value boolValue];
186 static BOOL (*_GSFontGetUseLegacyFontMetrics)();
187 #define $GSFontGetUseLegacyFontMetrics() \
188 (_GSFontGetUseLegacyFontMetrics == NULL ? YES : _GSFontGetUseLegacyFontMetrics())
190 static bool Debug_ = false;
191 static bool Engineer_ = false;
192 static bool SummerBoard_ = true;
193 static bool SpringBoard_;
195 static UIImage *(*_UIApplicationImageWithName)(NSString *name);
196 static UIImage *(*_UIImageWithNameInDomain)(NSString *name, NSString *domain);
197 static NSBundle *(*_UIKitBundle)();
198 static bool (*_UIPackedImageTableGetIdentifierForName)(NSString *, int *);
199 static int (*_UISharedImageNameGetIdentifier)(NSString *);
201 static NSMutableDictionary *UIImages_ = [[NSMutableDictionary alloc] initWithCapacity:32];
202 static NSMutableDictionary *PathImages_ = [[NSMutableDictionary alloc] initWithCapacity:16];
203 static NSMutableDictionary *Cache_ = [[NSMutableDictionary alloc] initWithCapacity:64];
204 static NSMutableDictionary *Strings_ = [[NSMutableDictionary alloc] initWithCapacity:0];
205 static NSMutableDictionary *Bundles_ = [[NSMutableDictionary alloc] initWithCapacity:2];
207 static NSFileManager *Manager_;
208 static NSMutableArray *Themes_;
210 static NSDictionary *English_;
211 static NSMutableDictionary *Info_;
214 static NSMutableDictionary *Themed_ = [[NSMutableDictionary alloc] initWithCapacity:128];
216 static unsigned Scale_ = 0;
218 static unsigned $getScale$(NSString *path) {
219 NSString *name(path);
221 #define StripName(strip) \
222 if ([name hasSuffix:@ strip]) \
223 name = [name substringWithRange:NSMakeRange(0, [name length] - sizeof(strip) - 1)];
227 StripName("~iphone");
230 return [name hasSuffix:@"@2x"] ? 2 : 1;
233 static NSString *$getTheme$(NSArray *files, bool rescale = false) {
234 if (NSString *path = [Themed_ objectForKey:files])
235 return reinterpret_cast<id>(path) == [NSNull null] ? nil : path;
237 if (rescale && Scale_ == 0) {
238 UIScreen *screen([UIScreen mainScreen]);
239 if ([screen respondsToSelector:@selector(scale)])
240 Scale_ = [screen scale];
246 NSLog(@"WB:Debug: %@", [files description]);
250 for (NSString *theme in Themes_)
251 for (NSString *file in files) {
252 if (rescale && /*$getScale$(file) == 1 &&*/ Scale_ == 2) {
253 path = [NSString stringWithFormat:@"%@/%@@2x.%@", theme, [file stringByDeletingPathExtension], [file pathExtension]];
254 if ([Manager_ fileExistsAtPath:path])
258 path = [NSString stringWithFormat:@"%@/%@", theme, file];
259 if ([Manager_ fileExistsAtPath:path])
266 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:files];
270 // $pathForFile$inBundle$() {{{
271 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool ui) {
272 NSString *identifier = [bundle bundleIdentifier];
273 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
275 if (identifier != nil)
276 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
277 if (NSString *folder = [[bundle bundlePath] lastPathComponent])
278 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
280 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
282 #define remapResourceName(oldname, newname) \
283 else if ([file isEqualToString:(oldname)]) \
284 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
286 bool summer(SpringBoard_ && SummerBoard_);
288 if (identifier == nil);
289 else if ([identifier isEqualToString:@"com.apple.chatkit"])
290 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
291 else if ([identifier isEqualToString:@"com.apple.calculator"])
292 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
294 remapResourceName(@"FSO_BG.png", @"StatusBar")
295 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
296 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
298 if (NSString *path = $getTheme$(names, ui))
305 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
306 NSString *identifier = [self bundleIdentifier];
307 NSString *path = [self path];
308 NSString *folder = [path lastPathComponent];
309 NSString *dname = [self displayName];
310 NSString *didentifier = [self displayIdentifier];
313 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
315 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
317 /* XXX: I might need to keep this for backwards compatibility
318 if (identifier != nil)
319 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
321 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
323 #define testForIcon(Name) \
324 if (NSString *name = Name) \
325 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
327 if (![didentifier isEqualToString:identifier])
328 testForIcon(didentifier);
330 testForIcon(identifier);
333 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
336 if (didentifier != nil) {
337 testForIcon([English_ objectForKey:didentifier]);
339 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
340 if ([parts count] != 1)
341 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
342 testForIcon([english objectForKey:[parts lastObject]]);
345 if (NSString *path = $getTheme$(names))
351 // -[NSBundle wb$bundleWithFile] {{{
352 @interface NSBundle (WinterBoard)
353 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
356 @implementation NSBundle (WinterBoard)
358 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
359 path = [path stringByDeletingLastPathComponent];
360 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
363 NSBundle *bundle([Bundles_ objectForKey:path]);
364 if (reinterpret_cast<id>(bundle) == [NSNull null])
366 else if (bundle == nil) {
367 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
368 bundle = [NSBundle bundleWithPath:path];
370 bundle = [NSBundle wb$bundleWithFile:path];
372 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
373 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
381 // -[NSString wb$themedPath] {{{
382 @interface NSString (WinterBoard)
383 - (NSString *) wb$themedPath;
386 @implementation NSString (WinterBoard)
388 - (NSString *) wb$themedPath {
389 if ([self hasPrefix:@"/Library/Themes/"])
393 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
395 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
396 NSString *file([self stringByResolvingSymlinksInPath]);
397 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
398 if ([file hasPrefix:prefix]) {
399 NSUInteger length([prefix length]);
400 if (length != [file length])
401 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
412 void WBLogRect(const char *tag, struct CGRect rect) {
413 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
416 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
417 CGRect frame([view frame]);
418 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]);
420 for (UIView *child in [view subviews])
421 WBLogHierarchy(child, index++, indent + 1);
424 UIImage *$cacheForImage$(UIImage *image) {
425 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
426 CGRect rect = {CGPointMake(1, 1), [image size]};
427 CGSize size = {rect.size.width + 2, rect.size.height + 2};
429 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
430 CGColorSpaceRelease(space);
432 CGContextDrawImage(context, rect, [image CGImage]);
433 CGImageRef ref(CGBitmapContextCreateImage(context));
434 CGContextRelease(context);
436 UIImage *cache([UIImage imageWithCGImage:ref]);
442 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
443 //if ([name isEqualToString:@"icons"]) return nil;
444 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
447 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
448 NSString *key([icon displayIdentifier]);
450 if (UIImage *image = [icon icon]) {
451 CGSize size = [image size];
452 if (size.width != 59 || size.height != 60) {
453 UIImage *cache($cacheForImage$(image));
454 [Cache_ setObject:cache forKey:key];
459 _SBIconModel$cacheImageForIcon$(self, sel, icon);
462 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
463 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
464 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
466 NSString *key([icon displayIdentifier]);
468 if (UIImage *image = [icon icon]) {
469 CGSize size = [image size];
470 if (size.width != 59 || size.height != 60) {
471 UIImage *cache($cacheForImage$(image));
472 [Cache_ setObject:cache forKey:key];
478 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
479 NSString *key([icon displayIdentifier]);
480 if (UIImage *image = [Cache_ objectForKey:key])
483 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
486 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
488 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
489 NSString *key([icon displayIdentifier]);
490 if (UIImage *image = [Cache_ objectForKey:key])
493 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
496 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
497 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
498 [self setBackgroundColor:[UIColor clearColor]];
499 for (UIView *child in [self subviews])
500 [child setBackgroundColor:[UIColor clearColor]];
504 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
505 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
506 [self setBackgroundColor:[UIColor clearColor]];
510 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
511 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
512 float inset([self edgeInset]);
513 [[UIColor clearColor] set];
514 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
515 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
518 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
519 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
520 if (NSString *path = $pathForIcon$([self application]))
521 return [UIImage imageWithContentsOfFile:path];
522 return _SBApplicationIcon$icon(self, sel);
525 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
527 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
528 if (IsWild_ && false) // XXX: delete this code, it should not be supported
529 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
530 return [UIImage imageWithContentsOfFile:path72];
531 if (NSString *path = $pathForIcon$([self application]))
532 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
534 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
535 width = [$SBIcon defaultIconImageSize].width;
538 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
541 return _SBApplicationIcon$generateIconImage$(self, sel, type);
544 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
546 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
547 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
548 return [UIImage imageWithContentsOfFile:path];
549 return _SBWidgetApplicationIcon$icon(self, sel);
552 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
554 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
555 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
556 return [UIImage imageWithContentsOfFile:path];
557 return _SBBookmarkIcon$icon(self, sel);
560 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
561 if (NSString *path = $pathForIcon$(self))
563 return _SBApplication$pathForIcon(self, sel);
566 static UIImage *CachedImageAtPath(NSString *path) {
567 path = [path stringByResolvingSymlinksInPath];
568 UIImage *image = [PathImages_ objectForKey:path];
570 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
571 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
573 image = [image autorelease];
574 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
578 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
579 NSBundle *bundle = [NSBundle mainBundle];
581 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
582 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
583 return CachedImageAtPath(path);
584 return __UIApplicationImageWithName(name);
587 #define WBDelegate(delegate) \
588 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
590 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
591 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
593 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
597 - (void) forwardInvocation:(NSInvocation*)inv { \
598 SEL sel = [inv selector]; \
599 if ([delegate respondsToSelector:sel]) \
600 [inv invokeWithTarget:delegate]; \
602 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
605 // %hook -[NSBundle pathForResource:ofType:] {{{
606 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
607 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
609 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
610 if (NSString *path = $pathForFile$inBundle$(file, self, false))
612 return MSOldCall(resource, type);
616 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
617 NSBundle *bundle([NSBundle mainBundle]);
619 CFLocaleRef locale(CFLocaleCopyCurrent());
620 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
623 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
625 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
626 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
627 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
628 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
632 CFRelease(formatter);
634 NSString *datestyle([@""
635 "font-family: Helvetica; "
636 "font-weight: bold; "
639 "" stringByAppendingString:(IsWild_
640 ? @"font-size: 54px; "
641 : @"font-size: 39px; "
644 NSString *daystyle([@""
645 "font-family: Helvetica; "
646 "font-weight: bold; "
648 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
649 "" stringByAppendingString:(IsWild_
650 ? @"font-size: 11px; "
651 : @"font-size: 9px; "
654 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
655 datestyle = [datestyle stringByAppendingString:style];
656 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
657 daystyle = [daystyle stringByAppendingString:style];
659 float width([self bounds].size.width);
661 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
662 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
664 unsigned base0(IsWild_ ? 89 : 70);
665 if ($GSFontGetUseLegacyFontMetrics())
667 unsigned base1(IsWild_ ? 18 : 16);
674 [(NSString *)date drawAtPoint:CGPointMake(
675 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
676 ) withStyle:datestyle];
678 [(NSString *)day drawAtPoint:CGPointMake(
679 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
680 ) withStyle:daystyle];
686 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
687 void $setBarStyle$_(NSString *name, int &style) {
689 NSLog(@"WB:Debug:%@Style:%d", name, style);
690 NSNumber *number = nil;
692 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
694 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
696 style = [number intValue];
698 NSLog(@"WB:Debug:%@Style=%d", name, style);
702 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
703 $setBarStyle$_(@"Toolbar", style);
704 return MSOldCall(style);
707 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
708 $setBarStyle$_(@"NavigationBar", style);
709 return MSOldCall(style);
713 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
714 [[self superview] setBackgroundColor:[UIColor clearColor]];
715 _SBButtonBar$didMoveToSuperview(self, sel);
718 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
719 [[self superview] setBackgroundColor:[UIColor clearColor]];
720 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
723 MSHook(UIImage *, UIImage$defaultDesktopImage, UIImage *self, SEL sel) {
725 NSLog(@"WB:Debug:DefaultDesktopImage");
726 if (NSString *path = $getTheme$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil]))
727 return [UIImage imageWithContentsOfFile:path];
728 return _UIImage$defaultDesktopImage(self, sel);
731 static NSArray *Wallpapers_;
732 static bool Papered_;
734 static NSString *WallpaperFile_;
735 static UIImageView *WallpaperImage_;
736 static UIWebDocumentView *WallpaperPage_;
737 static NSURL *WallpaperURL_;
739 #define _release(object) \
740 do if (object != nil) { \
745 static UIImage *$getImage$(NSString *path) {
746 UIImage *image([UIImage imageWithContentsOfFile:path]);
748 unsigned scale($getScale$(path));
749 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
750 [image setScale:scale];
755 // %hook -[SBUIController init] {{{
756 MSInstanceMessageHook0(id, SBUIController, init) {
761 NSString *paper($getTheme$(Wallpapers_, true));
765 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
766 char *machine = new char[size];
768 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
769 perror("sysctlbyname(\"hw.machine\", ?)");
774 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
777 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
779 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
780 [Info_ setObject:[NSNumber numberWithBool:(
781 !(paper != nil || GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"))) ||
782 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
783 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
784 )] forKey:@"UndockedIconLabels"];
787 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
790 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
791 if (&_wallpaperView != NULL) {
792 [_wallpaperView removeFromSuperview];
793 [_wallpaperView release];
794 _wallpaperView = nil;
798 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
799 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
802 if (&_contentLayer != NULL)
803 player = &_contentLayer;
804 else if (&_contentView != NULL)
805 player = &_contentView;
808 UIView *layer(player == NULL ? nil : *player);
810 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
811 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
812 [window setContentView:content];
814 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
815 [window setBackgroundColor:[_window backgroundColor]];
816 [_window setBackgroundColor:[UIColor clearColor]];
818 [window setLevel:-1000];
819 [window setHidden:NO];
821 /*if (player != NULL)
824 [content setBackgroundColor:[layer backgroundColor]];
825 [layer setBackgroundColor:[UIColor clearColor]];
828 if (!SummerBoard_ || !IsWild_)
831 CGRect bounds([content bounds]);
832 bounds.origin.y = -30;
833 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
834 [content addSubview:indirect];
835 [indirect zoomToScale:2.4];
838 _release(WallpaperFile_);
839 _release(WallpaperImage_);
840 _release(WallpaperPage_);
841 _release(WallpaperURL_);
843 if (NSString *path = paper) {
844 if ([path hasSuffix:@".mp4"]) {
848 static AVController *controller_(nil);
849 if (controller_ == nil) {
850 AVQueue *queue([AVQueue avQueue]);
851 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
854 AVQueue *queue([controller_ queue]);
856 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
857 [controller_ setLayer:[video _layer]];
859 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
860 [queue appendItem:item error:&error];
862 [controller_ play:&error];
863 #elif UseMPMoviePlayerController
864 NSURL *url([NSURL fileURLWithPath:path]);
865 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
866 controller.movieControlMode = MPMovieControlModeHidden;
869 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
870 [video setMovieWithPath:path];
871 [video setRepeatMode:1];
872 [video setRepeatGap:-1];
873 [video playFromBeginning];;
876 [indirect addSubview:video];
879 if ([path hasSuffix:@".png"] || [path hasSuffix:@".jpg"]) {
880 if (UIImage *image = $getImage$(path)) {
881 WallpaperFile_ = [path retain];
882 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
883 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
884 [WallpaperImage_ setAlpha:[number floatValue]];
885 [indirect addSubview:WallpaperImage_];
889 if ([path hasSuffix:@".html"]) {
890 CGRect bounds = [indirect bounds];
892 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
893 [view setAutoresizes:true];
895 WallpaperPage_ = [view retain];
896 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
898 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
900 [view setBackgroundColor:[UIColor clearColor]];
901 if ([view respondsToSelector:@selector(setDrawsBackground:)])
902 [view setDrawsBackground:NO];
903 [[view webView] setDrawsBackground:NO];
905 [indirect addSubview:view];
909 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
910 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
911 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
912 if ([Manager_ fileExistsAtPath:html]) {
913 CGRect bounds = [indirect bounds];
915 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
916 [view setAutoresizes:true];
918 NSURL *url = [NSURL fileURLWithPath:html];
919 [view loadRequest:[NSURLRequest requestWithURL:url]];
921 [view setBackgroundColor:[UIColor clearColor]];
922 if ([view respondsToSelector:@selector(setDrawsBackground:)])
923 [view setDrawsBackground:NO];
924 [[view webView] setDrawsBackground:NO];
926 [indirect addSubview:view];
934 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
935 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
936 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
938 if (path != nil && _backgroundView != nil)
941 _SBAwayView$updateDesktopImage$(self, sel, image);
944 CGRect bounds = [self bounds];
946 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
947 [view setAutoresizes:true];
949 if (WallpaperPage_ != nil)
950 [WallpaperPage_ release];
951 WallpaperPage_ = [view retain];
953 if (WallpaperURL_ != nil)
954 [WallpaperURL_ release];
955 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
957 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
959 [[view webView] setDrawsBackground:false];
960 [view setBackgroundColor:[UIColor clearColor]];
962 [self insertSubview:view aboveSubview:_backgroundView];
966 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
967 extern "C" CGColorRef CGGStateGetFillColor(void *);
968 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
969 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
971 /* WBTimeLabel {{{ */
972 @interface WBTimeLabel : NSProxy {
974 _transient SBStatusBarTimeView *view_;
977 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
981 @implementation WBTimeLabel
988 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
989 time_ = [time retain];
994 - (NSString *) description {
1000 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1001 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1002 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1004 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1005 "font-family: Helvetica; "
1006 "font-weight: bold; "
1009 "%@", _mode ? @"white" : @"black", custom]];
1014 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1019 /* WBBadgeLabel {{{ */
1020 @interface WBBadgeLabel : NSProxy {
1024 - (id) initWithBadge:(NSString *)badge;
1025 - (NSString *) description;
1029 @implementation WBBadgeLabel
1036 - (id) initWithBadge:(NSString *)badge {
1037 badge_ = [badge retain];
1041 - (NSString *) description {
1042 return [badge_ description];
1047 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1048 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1049 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1050 "font-family: Helvetica; "
1051 "font-weight: bold; "
1059 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1066 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1067 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1068 alpha = [number floatValue];
1069 return MSOldCall(alpha);
1072 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1073 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1074 alpha = [number floatValue];
1075 return MSOldCall(alpha);
1078 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1079 if ((self = MSOldCall()) != nil) {
1080 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1081 // XXX: note: this is overridden above, which is silly
1082 float alpha([number floatValue]);
1083 [self setIconImageAlpha:alpha];
1084 [self setIconLabelAlpha:alpha];
1089 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1090 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1091 alpha = [number floatValue];
1092 return MSOldCall(alpha);
1096 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1097 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1098 id &_badge(MSHookIvar<id>(self, "_badge"));
1100 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1105 void SBStatusBarController$setStatusBarMode(int &mode) {
1107 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1108 if (mode < 100) // 104:hidden 105:glowing
1109 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1110 mode = [number intValue];
1113 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1114 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1115 SBStatusBarController$setStatusBarMode(mode);
1116 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1119 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1120 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1121 SBStatusBarController$setStatusBarMode(mode);
1122 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1125 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) {
1126 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1127 SBStatusBarController$setStatusBarMode(mode);
1128 //NSLog(@"mode=%u", mode);
1129 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1132 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1133 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1134 mode = [number intValue];
1135 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1138 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1139 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1141 NSLog(@"operatorNameStyle= %@", style);
1142 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1143 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1147 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1149 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1150 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1153 // XXX: replace this with [SBStatusBarTimeView tile]
1154 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1155 id &_time(MSHookIvar<id>(self, "_time"));
1156 if (_time != nil && [_time class] != [WBTimeLabel class])
1157 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1158 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1161 @interface UIView (WinterBoard)
1162 - (bool) wb$isWBImageView;
1163 - (void) wb$logHierarchy;
1166 @implementation UIView (WinterBoard)
1168 - (bool) wb$isWBImageView {
1172 - (void) wb$logHierarchy {
1173 WBLogHierarchy(self);
1178 @interface WBImageView : UIImageView {
1181 - (bool) wb$isWBImageView;
1182 - (void) wb$updateFrame;
1185 @implementation WBImageView
1187 - (bool) wb$isWBImageView {
1191 - (void) wb$updateFrame {
1192 CGRect frame([self frame]);
1195 for (UIView *view(self); ; ) {
1196 view = [view superview];
1199 frame.origin.y -= [view frame].origin.y;
1202 [self setFrame:frame];
1207 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1208 NSArray *subviews([self subviews]);
1209 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1210 if (view != nil && [view wb$isWBImageView])
1211 [view wb$updateFrame];
1212 _SBIconList$setFrame$(self, sel, frame);
1215 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1216 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1217 NSArray *lists([_iconModel iconLists]);
1219 for (unsigned i(0), e([lists count]); i != e; ++i)
1220 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]])) {
1221 SBIconList *list([lists objectAtIndex:i]);
1222 NSArray *subviews([list subviews]);
1224 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1225 if (view == nil || ![view wb$isWBImageView]) {
1226 view = [[[WBImageView alloc] init] autorelease];
1227 [list insertSubview:view atIndex:0];
1230 UIImage *image([UIImage imageWithContentsOfFile:path]);
1232 CGRect frame([view frame]);
1233 frame.size = [image size];
1234 [view setFrame:frame];
1236 [view setImage:image];
1237 [view wb$updateFrame];
1240 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1243 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1244 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1246 [self setClipsToBounds:NO];
1250 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1251 id &_label(MSHookIvar<id>(self, "_label"));
1252 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1254 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1255 [_label setInDock:docked];
1256 return _SBIconLabel$setInDock$(self, sel, docked);
1259 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1260 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1263 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1264 _SBDockIconListView$setFrame$(self, sel, frame);
1267 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1268 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1269 NSString *identifier = [self bundleIdentifier];
1270 NSLocale *locale = [NSLocale currentLocale];
1271 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1273 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1274 NSString *file = table == nil ? @"Localizable" : table;
1275 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1276 NSDictionary *strings;
1277 if ((strings = [Strings_ objectForKey:name]) != nil) {
1278 if (static_cast<id>(strings) != [NSNull null]) strings:
1279 if (NSString *value = [strings objectForKey:key])
1281 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1284 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1285 [Strings_ setObject:[strings autorelease] forKey:name];
1289 [Strings_ setObject:[NSNull null] forKey:name];
1290 return MSOldCall(key, value, table);
1293 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1294 MSClassHook(WebCoreFrameBridge)
1296 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1299 void **core(reinterpret_cast<void **>([node _node]));
1300 if (core == NULL || core[6] == NULL)
1302 return MSOldCall(node, width);
1306 MSInstanceMessageHook1(void, SBIconLabel, drawRect, CGRect, rect) {
1307 CGRect bounds = [self bounds];
1309 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1312 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1313 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1315 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1317 NSString *style = [NSString stringWithFormat:@""
1318 "font-family: Helvetica; "
1319 "font-weight: bold; "
1321 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1322 ? @"font-size: 12px; "
1323 : @"font-size: 11px; "
1327 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1329 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1331 bool ellipsis(false);
1332 float max = 75, width;
1334 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
1337 size_t length([label length]);
1338 float spacing((width - max) / (length - 1));
1340 if (spacing > 1.25) {
1342 label = [label substringToIndex:(length - 1)];
1346 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
1350 label = [label stringByAppendingString:@"..."];
1352 if (NSString *custom = [Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")])
1353 style = [style stringByAppendingString:custom];
1355 CGSize size = [label sizeWithStyle:style forWidth:bounds.size.width];
1356 [label drawAtPoint:CGPointMake((bounds.size.width - size.width) / 2, 0) withStyle:style];
1360 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1362 [balloon setBackgroundColor:[UIColor clearColor]];
1365 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1366 if ((self = MSOldCall(style, reuse)) != nil) {
1367 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1371 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1372 if ((self = MSOldCall(style, reuse)) != nil) {
1373 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1374 [_label setBackgroundColor:[UIColor clearColor]];
1378 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1379 MSOldCall(UITableViewCellSeparatorStyleNone);
1382 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1383 if ((self = MSOldCall(frame, style)) != nil) {
1384 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1388 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1391 if (NSString *path = $getTheme$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil]))
1392 if (UIImage *image = [[UIImage alloc] initWithContentsOfFile:path]) {
1393 [image autorelease];
1395 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1396 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1398 if (&_transcriptTable != NULL)
1399 table = _transcriptTable;
1400 else if (&_transcriptLayer != NULL)
1401 table = _transcriptLayer;
1405 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1406 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1409 [placard insertSubview:background atIndex:0];
1411 [table setBackgroundColor:[UIColor clearColor]];
1412 [placard insertSubview:background belowSubview:table];
1418 // %hook _UIImageWithName() {{{
1419 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1421 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1428 if (_UIPackedImageTableGetIdentifierForName != NULL)
1429 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1430 else if (_UISharedImageNameGetIdentifier != NULL) {
1431 identifier = _UISharedImageNameGetIdentifier(name);
1432 packed = identifier != -1;
1439 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1442 return __UIImageWithName(name);
1444 NSNumber *key([NSNumber numberWithInt:identifier]);
1445 UIImage *image([UIImages_ objectForKey:key]);
1447 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1448 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1449 image = $getImage$(path);
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 = $getImage$(path);
1465 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1466 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1470 // %hook GSFontCreateWithName() {{{
1471 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1473 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1474 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1475 name = [font UTF8String];
1476 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1477 // size *= [scale floatValue];
1478 return _GSFontCreateWithName(name, traits, size);
1482 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1483 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1485 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1487 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1489 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1490 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1492 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1495 NSString *path = [NSString stringWithUTF8String:a1];
1496 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1497 NSString *file = [path substringFromIndex:31];
1498 for (NSString *theme in Themes_) {
1499 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1500 if ([Manager_ fileExistsAtPath:path]) {
1501 strcpy(a1, [path UTF8String]);
1510 static void ChangeWallpaper(
1511 CFNotificationCenterRef center,
1515 CFDictionaryRef info
1518 NSLog(@"WB:Debug:ChangeWallpaper!");
1521 if (WallpaperFile_ != nil) {
1522 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1524 image = [image autorelease];
1527 if (WallpaperImage_ != nil)
1528 [WallpaperImage_ setImage:image];
1529 if (WallpaperPage_ != nil)
1530 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1534 #define WBRename(name, sel, imp) \
1535 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
1537 template <typename Type_>
1538 static void msset(Type_ &function, MSImageRef image, const char *name) {
1539 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1542 template <typename Type_>
1543 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1544 struct nlist &name(nl[index]);
1545 uintptr_t value(name.n_value);
1546 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1547 value |= 0x00000001;
1548 function = reinterpret_cast<Type_>(value);
1551 template <typename Type_>
1552 static void dlset(Type_ &function, const char *name) {
1553 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1556 // %hook CGImageReadCreateWithFile() {{{
1557 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1559 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1560 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1561 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1567 extern "C" void WKSetCurrentGraphicsContext(CGContextRef);
1569 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
1570 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1571 if (style == nil || [style length] == 0)
1572 style = @"font-family: Helvetica; font-size: 12px";
1573 return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
1576 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
1577 if (style == nil || [style length] == 0)
1578 style = @"font-family: Helvetica; font-size: 12px";
1579 return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width];
1582 static void SBInitialize() {
1583 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
1584 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
1586 _UIImage$defaultDesktopImage = MSHookMessage(object_getClass($UIImage), @selector(defaultDesktopImage), &$UIImage$defaultDesktopImage);
1589 WBRename(SBApplication, pathForIcon, pathForIcon);
1590 WBRename(SBApplicationIcon, icon, icon);
1591 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1594 WBRename(SBBookmarkIcon, icon, icon);
1595 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1596 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1597 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1598 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
1600 WBRename(SBWidgetApplicationIcon, icon, icon);
1602 WBRename(SBDockIconListView, setFrame:, setFrame$);
1603 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
1605 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
1606 WBRename(SBIconLabel, setInDock:, setInDock$);
1608 WBRename(SBIconList, setFrame:, setFrame$);
1610 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
1611 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
1612 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
1613 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
1615 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
1616 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
1617 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
1619 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
1621 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
1622 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
1623 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
1624 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
1625 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
1626 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
1627 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
1628 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
1629 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
1632 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
1636 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1638 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
1639 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
1641 Manager_ = [[NSFileManager defaultManager] retain];
1642 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
1644 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
1646 // Load Settings.plist {{{
1647 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
1648 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
1649 SummerBoard_ = [value boolValue];
1650 if (NSNumber *value = [settings objectForKey:@"Debug"])
1651 Debug_ = [value boolValue];
1653 NSArray *themes([settings objectForKey:@"Themes"]);
1655 if (NSString *theme = [settings objectForKey:@"Theme"])
1656 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
1658 [NSNumber numberWithBool:true], @"Active",
1662 for (NSDictionary *theme in themes) {
1663 NSNumber *active([theme objectForKey:@"Active"]);
1664 if (![active boolValue])
1667 NSString *name([theme objectForKey:@"Name"]);
1671 NSString *theme(nil);
1673 #define testForTheme(format...) \
1674 if (theme == nil) { \
1675 NSString *path = [NSString stringWithFormat:format]; \
1676 if ([Manager_ fileExistsAtPath:path]) { \
1677 [Themes_ addObject:path]; \
1682 testForTheme(@"/Library/Themes/%@.theme", name)
1683 testForTheme(@"/Library/Themes/%@", name)
1684 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
1689 // Merge Info.plist {{{
1690 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1692 for (NSString *theme in Themes_)
1693 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
1694 for (NSString *key in [info allKeys])
1695 if ([Info_ objectForKey:key] == nil)
1696 [Info_ setObject:[info objectForKey:key] forKey:key];
1700 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
1701 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
1702 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
1705 // GraphicsServices {{{
1707 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
1711 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
1712 void *(*CGImageReadCreateWithFile)(NSString *, int);
1713 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
1714 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
1719 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
1720 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]);
1722 CFNotificationCenterAddObserver(
1723 CFNotificationCenterGetDarwinNotifyCenter(),
1724 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
1727 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
1728 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
1729 if (MediaPlayer != nil)
1732 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
1733 $MPVideoView = objc_getClass("MPVideoView");
1740 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
1742 memset(nl, 0, sizeof(nl));
1743 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
1744 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
1745 nl[2].n_un.n_name = (char *) "__UIKitBundle";
1746 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
1747 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
1750 nlset(_UIApplicationImageWithName, nl, 0);
1751 nlset(_UIImageWithNameInDomain, nl, 1);
1752 nlset(_UIKitBundle, nl, 2);
1753 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
1754 nlset(_UISharedImageNameGetIdentifier, nl, 4);
1756 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
1757 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
1758 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);