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 NSString *$getTheme$(NSArray *files, bool rescale = false) {
216 if (NSString *path = [Themed_ objectForKey:files])
217 return reinterpret_cast<id>(path) == [NSNull null] ? nil : path;
219 if (rescale && Scale_ == 0) {
220 UIScreen *screen([UIScreen mainScreen]);
221 if ([screen respondsToSelector:@selector(scale)])
222 Scale_ = [screen scale];
228 NSLog(@"WB:Debug: %@", [files description]);
232 for (NSString *theme in Themes_)
233 for (NSString *file in files) {
234 path = [NSString stringWithFormat:@"%@/%@", theme, file];
235 if ([Manager_ fileExistsAtPath:path])
242 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:files];
246 // $pathForFile$inBundle$() {{{
247 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool ui) {
248 NSString *identifier = [bundle bundleIdentifier];
249 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
251 if (identifier != nil)
252 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
253 if (NSString *folder = [[bundle bundlePath] lastPathComponent])
254 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
256 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
258 #define remapResourceName(oldname, newname) \
259 else if ([file isEqualToString:(oldname)]) \
260 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
262 bool summer(SpringBoard_ && SummerBoard_);
264 if (identifier == nil);
265 else if ([identifier isEqualToString:@"com.apple.chatkit"])
266 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
267 else if ([identifier isEqualToString:@"com.apple.calculator"])
268 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
270 remapResourceName(@"FSO_BG.png", @"StatusBar")
271 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
272 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
274 if (NSString *path = $getTheme$(names, ui))
281 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
282 NSString *identifier = [self bundleIdentifier];
283 NSString *path = [self path];
284 NSString *folder = [path lastPathComponent];
285 NSString *dname = [self displayName];
286 NSString *didentifier = [self displayIdentifier];
289 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
291 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
293 /* XXX: I might need to keep this for backwards compatibility
294 if (identifier != nil)
295 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
297 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
299 #define testForIcon(Name) \
300 if (NSString *name = Name) \
301 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
303 if (![didentifier isEqualToString:identifier])
304 testForIcon(didentifier);
306 testForIcon(identifier);
309 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
312 if (didentifier != nil) {
313 testForIcon([English_ objectForKey:didentifier]);
315 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
316 if ([parts count] != 1)
317 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
318 testForIcon([english objectForKey:[parts lastObject]]);
321 if (NSString *path = $getTheme$(names))
327 // -[NSBundle wb$bundleWithFile] {{{
328 @interface NSBundle (WinterBoard)
329 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
332 @implementation NSBundle (WinterBoard)
334 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
335 path = [path stringByDeletingLastPathComponent];
336 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
339 NSBundle *bundle([Bundles_ objectForKey:path]);
340 if (reinterpret_cast<id>(bundle) == [NSNull null])
342 else if (bundle == nil) {
343 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
344 bundle = [NSBundle bundleWithPath:path];
346 bundle = [NSBundle wb$bundleWithFile:path];
348 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
349 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
357 // -[NSString wb$themedPath] {{{
358 @interface NSString (WinterBoard)
359 - (NSString *) wb$themedPath;
362 @implementation NSString (WinterBoard)
364 - (NSString *) wb$themedPath {
366 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
368 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
369 NSString *file([self stringByResolvingSymlinksInPath]);
370 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
371 if ([file hasPrefix:prefix]) {
372 NSUInteger length([prefix length]);
373 if (length != [file length])
374 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
385 void WBLogRect(const char *tag, struct CGRect rect) {
386 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
389 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
390 CGRect frame([view frame]);
391 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]);
393 for (UIView *child in [view subviews])
394 WBLogHierarchy(child, index++, indent + 1);
397 UIImage *$cacheForImage$(UIImage *image) {
398 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
399 CGRect rect = {CGPointMake(1, 1), [image size]};
400 CGSize size = {rect.size.width + 2, rect.size.height + 2};
402 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
403 CGColorSpaceRelease(space);
405 CGContextDrawImage(context, rect, [image CGImage]);
406 CGImageRef ref(CGBitmapContextCreateImage(context));
407 CGContextRelease(context);
409 UIImage *cache([UIImage imageWithCGImage:ref]);
415 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
416 //if ([name isEqualToString:@"icons"]) return nil;
417 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
420 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
421 NSString *key([icon displayIdentifier]);
423 if (UIImage *image = [icon icon]) {
424 CGSize size = [image size];
425 if (size.width != 59 || size.height != 60) {
426 UIImage *cache($cacheForImage$(image));
427 [Cache_ setObject:cache forKey:key];
432 _SBIconModel$cacheImageForIcon$(self, sel, icon);
435 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
436 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
437 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
439 NSString *key([icon displayIdentifier]);
441 if (UIImage *image = [icon icon]) {
442 CGSize size = [image size];
443 if (size.width != 59 || size.height != 60) {
444 UIImage *cache($cacheForImage$(image));
445 [Cache_ setObject:cache forKey:key];
451 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
452 NSString *key([icon displayIdentifier]);
453 if (UIImage *image = [Cache_ objectForKey:key])
456 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
459 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
461 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
462 NSString *key([icon displayIdentifier]);
463 if (UIImage *image = [Cache_ objectForKey:key])
466 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
469 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
470 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
471 [self setBackgroundColor:[UIColor clearColor]];
472 for (UIView *child in [self subviews])
473 [child setBackgroundColor:[UIColor clearColor]];
477 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
478 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
479 [self setBackgroundColor:[UIColor clearColor]];
483 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
484 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
485 float inset([self edgeInset]);
486 [[UIColor clearColor] set];
487 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
488 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
491 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
492 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
493 if (NSString *path = $pathForIcon$([self application]))
494 return [UIImage imageWithContentsOfFile:path];
495 return _SBApplicationIcon$icon(self, sel);
498 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
500 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
501 if (IsWild_ && false) // XXX: delete this code, it should not be supported
502 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
503 return [UIImage imageWithContentsOfFile:path72];
504 if (NSString *path = $pathForIcon$([self application]))
505 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
507 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
508 width = [$SBIcon defaultIconImageSize].width;
511 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
514 return _SBApplicationIcon$generateIconImage$(self, sel, type);
517 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
519 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
520 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
521 return [UIImage imageWithContentsOfFile:path];
522 return _SBWidgetApplicationIcon$icon(self, sel);
525 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
527 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
528 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
529 return [UIImage imageWithContentsOfFile:path];
530 return _SBBookmarkIcon$icon(self, sel);
533 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
534 if (NSString *path = $pathForIcon$(self))
536 return _SBApplication$pathForIcon(self, sel);
539 static UIImage *CachedImageAtPath(NSString *path) {
540 path = [path stringByResolvingSymlinksInPath];
541 UIImage *image = [PathImages_ objectForKey:path];
543 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
544 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
546 image = [image autorelease];
547 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
551 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
552 NSBundle *bundle = [NSBundle mainBundle];
554 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
555 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
556 return CachedImageAtPath(path);
557 return __UIApplicationImageWithName(name);
560 #define WBDelegate(delegate) \
561 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
563 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
564 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
566 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
570 - (void) forwardInvocation:(NSInvocation*)inv { \
571 SEL sel = [inv selector]; \
572 if ([delegate respondsToSelector:sel]) \
573 [inv invokeWithTarget:delegate]; \
575 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
578 // %hook -[NSBundle pathForResource:ofType:] {{{
579 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
580 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
582 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
583 if (NSString *path = $pathForFile$inBundle$(file, self, false))
585 return MSOldCall(resource, type);
589 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
590 NSBundle *bundle([NSBundle mainBundle]);
592 CFLocaleRef locale(CFLocaleCopyCurrent());
593 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
596 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
598 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
599 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
600 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
601 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
605 CFRelease(formatter);
607 NSString *datestyle([@""
608 "font-family: Helvetica; "
609 "font-weight: bold; "
612 "" stringByAppendingString:(IsWild_
613 ? @"font-size: 54px; "
614 : @"font-size: 39px; "
617 NSString *daystyle([@""
618 "font-family: Helvetica; "
619 "font-weight: bold; "
621 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
622 "" stringByAppendingString:(IsWild_
623 ? @"font-size: 11px; "
624 : @"font-size: 9px; "
627 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
628 datestyle = [datestyle stringByAppendingString:style];
629 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
630 daystyle = [daystyle stringByAppendingString:style];
632 float width([self bounds].size.width);
634 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
635 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
637 unsigned base0(IsWild_ ? 89 : 70);
638 if ($GSFontGetUseLegacyFontMetrics())
640 unsigned base1(IsWild_ ? 18 : 16);
647 [(NSString *)date drawAtPoint:CGPointMake(
648 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
649 ) withStyle:datestyle];
651 [(NSString *)day drawAtPoint:CGPointMake(
652 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
653 ) withStyle:daystyle];
659 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
660 void $setBarStyle$_(NSString *name, int &style) {
662 NSLog(@"WB:Debug:%@Style:%d", name, style);
663 NSNumber *number = nil;
665 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
667 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
669 style = [number intValue];
671 NSLog(@"WB:Debug:%@Style=%d", name, style);
675 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
676 $setBarStyle$_(@"Toolbar", style);
677 return MSOldCall(style);
680 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
681 $setBarStyle$_(@"NavigationBar", style);
682 return MSOldCall(style);
686 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
687 [[self superview] setBackgroundColor:[UIColor clearColor]];
688 _SBButtonBar$didMoveToSuperview(self, sel);
691 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
692 [[self superview] setBackgroundColor:[UIColor clearColor]];
693 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
696 MSHook(UIImage *, UIImage$defaultDesktopImage, UIImage *self, SEL sel) {
698 NSLog(@"WB:Debug:DefaultDesktopImage");
699 if (NSString *path = $getTheme$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil]))
700 return [UIImage imageWithContentsOfFile:path];
701 return _UIImage$defaultDesktopImage(self, sel);
704 static NSArray *Wallpapers_;
705 static bool Papered_;
707 static NSString *WallpaperFile_;
708 static UIImageView *WallpaperImage_;
709 static UIWebDocumentView *WallpaperPage_;
710 static NSURL *WallpaperURL_;
712 #define _release(object) \
713 do if (object != nil) { \
718 static UIImage *$getImage$(NSString *path) {
719 NSString *name(path);
721 #define StripName(strip) \
722 if ([name hasSuffix:@ strip]) \
723 name = [name substringWithRange:NSMakeRange(0, [name length] - sizeof(strip) - 1)];
727 StripName("~iphone");
730 unsigned scale([name hasSuffix:@"@2x"] ? 2 : 1);
732 UIImage *image([UIImage imageWithContentsOfFile:path]);
734 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
735 [image setScale:scale];
740 // %hook -[SBUIController init] {{{
741 MSInstanceMessageHook0(id, SBUIController, init) {
746 NSString *paper($getTheme$(Wallpapers_, true));
750 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
751 char *machine = new char[size];
753 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
754 perror("sysctlbyname(\"hw.machine\", ?)");
759 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
762 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
764 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
765 [Info_ setObject:[NSNumber numberWithBool:(
766 !(paper != nil || GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"))) ||
767 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
768 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
769 )] forKey:@"UndockedIconLabels"];
772 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
775 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
776 if (&_wallpaperView != NULL) {
777 [_wallpaperView removeFromSuperview];
778 [_wallpaperView release];
779 _wallpaperView = nil;
783 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
784 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
787 if (&_contentLayer != NULL)
788 player = &_contentLayer;
789 else if (&_contentView != NULL)
790 player = &_contentView;
793 UIView *layer(player == NULL ? nil : *player);
795 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
796 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
797 [window setContentView:content];
799 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
800 [window setBackgroundColor:[_window backgroundColor]];
801 [_window setBackgroundColor:[UIColor clearColor]];
803 [window setLevel:-1000];
804 [window setHidden:NO];
806 /*if (player != NULL)
809 [content setBackgroundColor:[layer backgroundColor]];
810 [layer setBackgroundColor:[UIColor clearColor]];
813 if (!SummerBoard_ || !IsWild_)
816 CGRect bounds([content bounds]);
817 bounds.origin.y = -30;
818 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
819 [content addSubview:indirect];
820 [indirect zoomToScale:2.4];
823 _release(WallpaperFile_);
824 _release(WallpaperImage_);
825 _release(WallpaperPage_);
826 _release(WallpaperURL_);
828 if (NSString *path = paper) {
829 if ([path hasSuffix:@".mp4"]) {
833 static AVController *controller_(nil);
834 if (controller_ == nil) {
835 AVQueue *queue([AVQueue avQueue]);
836 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
839 AVQueue *queue([controller_ queue]);
841 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
842 [controller_ setLayer:[video _layer]];
844 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
845 [queue appendItem:item error:&error];
847 [controller_ play:&error];
848 #elif UseMPMoviePlayerController
849 NSURL *url([NSURL fileURLWithPath:path]);
850 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
851 controller.movieControlMode = MPMovieControlModeHidden;
854 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
855 [video setMovieWithPath:path];
856 [video setRepeatMode:1];
857 [video setRepeatGap:-1];
858 [video playFromBeginning];;
861 [indirect addSubview:video];
864 if ([path hasSuffix:@".png"] || [path hasSuffix:@".jpg"]) {
865 if (UIImage *image = $getImage$(path)) {
866 WallpaperFile_ = [path retain];
867 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
868 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
869 [WallpaperImage_ setAlpha:[number floatValue]];
870 [indirect addSubview:WallpaperImage_];
874 if ([path hasSuffix:@".html"]) {
875 CGRect bounds = [indirect bounds];
877 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
878 [view setAutoresizes:true];
880 WallpaperPage_ = [view retain];
881 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
883 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
885 [view setBackgroundColor:[UIColor clearColor]];
886 if ([view respondsToSelector:@selector(setDrawsBackground:)])
887 [view setDrawsBackground:NO];
888 [[view webView] setDrawsBackground:NO];
890 [indirect addSubview:view];
894 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
895 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
896 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
897 if ([Manager_ fileExistsAtPath:html]) {
898 CGRect bounds = [indirect bounds];
900 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
901 [view setAutoresizes:true];
903 NSURL *url = [NSURL fileURLWithPath:html];
904 [view loadRequest:[NSURLRequest requestWithURL:url]];
906 [view setBackgroundColor:[UIColor clearColor]];
907 if ([view respondsToSelector:@selector(setDrawsBackground:)])
908 [view setDrawsBackground:NO];
909 [[view webView] setDrawsBackground:NO];
911 [indirect addSubview:view];
919 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
920 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
921 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
923 if (path != nil && _backgroundView != nil)
926 _SBAwayView$updateDesktopImage$(self, sel, image);
929 CGRect bounds = [self bounds];
931 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
932 [view setAutoresizes:true];
934 if (WallpaperPage_ != nil)
935 [WallpaperPage_ release];
936 WallpaperPage_ = [view retain];
938 if (WallpaperURL_ != nil)
939 [WallpaperURL_ release];
940 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
942 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
944 [[view webView] setDrawsBackground:false];
945 [view setBackgroundColor:[UIColor clearColor]];
947 [self insertSubview:view aboveSubview:_backgroundView];
951 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
952 extern "C" CGColorRef CGGStateGetFillColor(void *);
953 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
954 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
956 /* WBTimeLabel {{{ */
957 @interface WBTimeLabel : NSProxy {
959 _transient SBStatusBarTimeView *view_;
962 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
966 @implementation WBTimeLabel
973 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
974 time_ = [time retain];
979 - (NSString *) description {
985 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
986 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
987 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
989 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
990 "font-family: Helvetica; "
991 "font-weight: bold; "
994 "%@", _mode ? @"white" : @"black", custom]];
999 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1004 /* WBBadgeLabel {{{ */
1005 @interface WBBadgeLabel : NSProxy {
1009 - (id) initWithBadge:(NSString *)badge;
1010 - (NSString *) description;
1014 @implementation WBBadgeLabel
1021 - (id) initWithBadge:(NSString *)badge {
1022 badge_ = [badge retain];
1026 - (NSString *) description {
1027 return [badge_ description];
1032 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1033 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1034 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1035 "font-family: Helvetica; "
1036 "font-weight: bold; "
1044 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1051 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1052 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1053 alpha = [number floatValue];
1054 return MSOldCall(alpha);
1057 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1058 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1059 alpha = [number floatValue];
1060 return MSOldCall(alpha);
1063 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1064 if ((self = MSOldCall()) != nil) {
1065 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1066 // XXX: note: this is overridden above, which is silly
1067 float alpha([number floatValue]);
1068 [self setIconImageAlpha:alpha];
1069 [self setIconLabelAlpha:alpha];
1074 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1075 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1076 alpha = [number floatValue];
1077 return MSOldCall(alpha);
1081 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1082 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1083 id &_badge(MSHookIvar<id>(self, "_badge"));
1085 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1090 void SBStatusBarController$setStatusBarMode(int &mode) {
1092 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1093 if (mode < 100) // 104:hidden 105:glowing
1094 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1095 mode = [number intValue];
1098 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1099 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1100 SBStatusBarController$setStatusBarMode(mode);
1101 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1104 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1105 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1106 SBStatusBarController$setStatusBarMode(mode);
1107 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1110 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) {
1111 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1112 SBStatusBarController$setStatusBarMode(mode);
1113 //NSLog(@"mode=%u", mode);
1114 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1117 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1118 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1119 mode = [number intValue];
1120 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1123 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1124 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1126 NSLog(@"operatorNameStyle= %@", style);
1127 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1128 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1132 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1134 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1135 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1138 // XXX: replace this with [SBStatusBarTimeView tile]
1139 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1140 id &_time(MSHookIvar<id>(self, "_time"));
1141 if (_time != nil && [_time class] != [WBTimeLabel class])
1142 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1143 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1146 @interface UIView (WinterBoard)
1147 - (bool) wb$isWBImageView;
1148 - (void) wb$logHierarchy;
1151 @implementation UIView (WinterBoard)
1153 - (bool) wb$isWBImageView {
1157 - (void) wb$logHierarchy {
1158 WBLogHierarchy(self);
1163 @interface WBImageView : UIImageView {
1166 - (bool) wb$isWBImageView;
1167 - (void) wb$updateFrame;
1170 @implementation WBImageView
1172 - (bool) wb$isWBImageView {
1176 - (void) wb$updateFrame {
1177 CGRect frame([self frame]);
1180 for (UIView *view(self); ; ) {
1181 view = [view superview];
1184 frame.origin.y -= [view frame].origin.y;
1187 [self setFrame:frame];
1192 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1193 NSArray *subviews([self subviews]);
1194 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1195 if (view != nil && [view wb$isWBImageView])
1196 [view wb$updateFrame];
1197 _SBIconList$setFrame$(self, sel, frame);
1200 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1201 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1202 NSArray *lists([_iconModel iconLists]);
1204 for (unsigned i(0), e([lists count]); i != e; ++i)
1205 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]])) {
1206 SBIconList *list([lists objectAtIndex:i]);
1207 NSArray *subviews([list subviews]);
1209 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1210 if (view == nil || ![view wb$isWBImageView]) {
1211 view = [[[WBImageView alloc] init] autorelease];
1212 [list insertSubview:view atIndex:0];
1215 UIImage *image([UIImage imageWithContentsOfFile:path]);
1217 CGRect frame([view frame]);
1218 frame.size = [image size];
1219 [view setFrame:frame];
1221 [view setImage:image];
1222 [view wb$updateFrame];
1225 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1228 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1229 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1231 [self setClipsToBounds:NO];
1235 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1236 id &_label(MSHookIvar<id>(self, "_label"));
1237 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1239 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1240 [_label setInDock:docked];
1241 return _SBIconLabel$setInDock$(self, sel, docked);
1244 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1245 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1248 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1249 _SBDockIconListView$setFrame$(self, sel, frame);
1252 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1253 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1254 NSString *identifier = [self bundleIdentifier];
1255 NSLocale *locale = [NSLocale currentLocale];
1256 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1258 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1259 NSString *file = table == nil ? @"Localizable" : table;
1260 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1261 NSDictionary *strings;
1262 if ((strings = [Strings_ objectForKey:name]) != nil) {
1263 if (static_cast<id>(strings) != [NSNull null]) strings:
1264 if (NSString *value = [strings objectForKey:key])
1266 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1269 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1270 [Strings_ setObject:[strings autorelease] forKey:name];
1274 [Strings_ setObject:[NSNull null] forKey:name];
1275 return MSOldCall(key, value, table);
1278 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1279 MSClassHook(WebCoreFrameBridge)
1281 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1284 void **core(reinterpret_cast<void **>([node _node]));
1285 if (core == NULL || core[6] == NULL)
1287 return MSOldCall(node, width);
1291 MSHook(void, SBIconLabel$drawRect$, SBIconLabel *self, SEL sel, CGRect rect) {
1292 CGRect bounds = [self bounds];
1294 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1297 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1298 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1300 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1302 NSString *style = [NSString stringWithFormat:@""
1303 "font-family: Helvetica; "
1304 "font-weight: bold; "
1306 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1307 ? @"font-size: 12px; "
1308 : @"font-size: 11px; "
1312 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1314 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1316 bool ellipsis(false);
1317 float max = 75, width;
1319 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
1322 size_t length([label length]);
1323 float spacing((width - max) / (length - 1));
1325 if (spacing > 1.25) {
1327 label = [label substringToIndex:(length - 1)];
1331 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
1335 label = [label stringByAppendingString:@"..."];
1337 if (NSString *custom = [Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")])
1338 style = [style stringByAppendingString:custom];
1340 CGSize size = [label sizeWithStyle:style forWidth:bounds.size.width];
1341 [label drawAtPoint:CGPointMake((bounds.size.width - size.width) / 2, 0) withStyle:style];
1345 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1347 [balloon setBackgroundColor:[UIColor clearColor]];
1350 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1351 if ((self = MSOldCall(style, reuse)) != nil) {
1352 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1356 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1357 if ((self = MSOldCall(style, reuse)) != nil) {
1358 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1359 [_label setBackgroundColor:[UIColor clearColor]];
1363 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1364 MSOldCall(UITableViewCellSeparatorStyleNone);
1367 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1368 if ((self = MSOldCall(frame, style)) != nil) {
1369 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1373 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1376 if (NSString *path = $getTheme$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil]))
1377 if (UIImage *image = [[UIImage alloc] initWithContentsOfFile:path]) {
1378 [image autorelease];
1380 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1381 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1383 if (&_transcriptTable != NULL)
1384 table = _transcriptTable;
1385 else if (&_transcriptLayer != NULL)
1386 table = _transcriptLayer;
1390 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1391 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1394 [placard insertSubview:background atIndex:0];
1396 [table setBackgroundColor:[UIColor clearColor]];
1397 [placard insertSubview:background belowSubview:table];
1403 // %hook _UIImageWithName() {{{
1404 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1406 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1413 if (_UIPackedImageTableGetIdentifierForName != NULL)
1414 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1415 else if (_UISharedImageNameGetIdentifier != NULL) {
1416 identifier = _UISharedImageNameGetIdentifier(name);
1417 packed = identifier != -1;
1424 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1427 return __UIImageWithName(name);
1429 NSNumber *key([NSNumber numberWithInt:identifier]);
1430 UIImage *image([UIImages_ objectForKey:key]);
1432 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1433 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true)) {
1434 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
1436 [image autorelease];
1438 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1439 return image == nil ? __UIImageWithName(name) : image;
1443 // %hook _UIImageWithNameInDomain() {{{
1444 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1445 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1446 UIImage *image([PathImages_ objectForKey:key]);
1448 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1450 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1451 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]], true)) {
1452 image = [[UIImage alloc] initWithContentsOfFile:path];
1454 [image autorelease];
1456 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1457 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1461 // %hook GSFontCreateWithName() {{{
1462 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1464 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1465 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1466 name = [font UTF8String];
1467 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1468 // size *= [scale floatValue];
1469 return _GSFontCreateWithName(name, traits, size);
1473 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1474 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1476 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1478 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1480 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1481 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1483 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1486 NSString *path = [NSString stringWithUTF8String:a1];
1487 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1488 NSString *file = [path substringFromIndex:31];
1489 for (NSString *theme in Themes_) {
1490 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1491 if ([Manager_ fileExistsAtPath:path]) {
1492 strcpy(a1, [path UTF8String]);
1501 static void ChangeWallpaper(
1502 CFNotificationCenterRef center,
1506 CFDictionaryRef info
1509 NSLog(@"WB:Debug:ChangeWallpaper!");
1512 if (WallpaperFile_ != nil) {
1513 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1515 image = [image autorelease];
1518 if (WallpaperImage_ != nil)
1519 [WallpaperImage_ setImage:image];
1520 if (WallpaperPage_ != nil)
1521 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1525 #define WBRename(name, sel, imp) \
1526 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
1528 template <typename Type_>
1529 static void msset(Type_ &function, MSImageRef image, const char *name) {
1530 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1533 template <typename Type_>
1534 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1535 struct nlist &name(nl[index]);
1536 uintptr_t value(name.n_value);
1537 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1538 value |= 0x00000001;
1539 function = reinterpret_cast<Type_>(value);
1542 template <typename Type_>
1543 static void dlset(Type_ &function, const char *name) {
1544 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1547 // %hook CGImageReadCreateWithFile() {{{
1548 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1550 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1551 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1552 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1558 static void SBInitialize() {
1559 _UIImage$defaultDesktopImage = MSHookMessage(object_getClass($UIImage), @selector(defaultDesktopImage), &$UIImage$defaultDesktopImage);
1561 bool olden(dlsym(RTLD_DEFAULT, "GSLibraryCopyGenerationInfoValueForKey") == NULL);
1564 WBRename(SBApplication, pathForIcon, pathForIcon);
1565 WBRename(SBApplicationIcon, icon, icon);
1566 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1569 WBRename(SBBookmarkIcon, icon, icon);
1570 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1571 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1572 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1573 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
1575 WBRename(SBWidgetApplicationIcon, icon, icon);
1577 WBRename(SBDockIconListView, setFrame:, setFrame$);
1578 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
1581 WBRename(SBIconLabel, drawRect:, drawRect$);
1583 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
1584 WBRename(SBIconLabel, setInDock:, setInDock$);
1586 WBRename(SBIconList, setFrame:, setFrame$);
1588 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
1589 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
1590 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
1591 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
1593 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
1594 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
1595 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
1597 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
1599 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
1600 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
1601 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
1602 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
1603 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
1604 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
1605 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
1606 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
1607 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
1610 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
1614 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1616 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
1617 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
1619 Manager_ = [[NSFileManager defaultManager] retain];
1620 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
1622 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
1624 // Load Settings.plist {{{
1625 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
1626 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
1627 SummerBoard_ = [value boolValue];
1628 if (NSNumber *value = [settings objectForKey:@"Debug"])
1629 Debug_ = [value boolValue];
1631 NSArray *themes([settings objectForKey:@"Themes"]);
1633 if (NSString *theme = [settings objectForKey:@"Theme"])
1634 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
1636 [NSNumber numberWithBool:true], @"Active",
1640 for (NSDictionary *theme in themes) {
1641 NSNumber *active([theme objectForKey:@"Active"]);
1642 if (![active boolValue])
1645 NSString *name([theme objectForKey:@"Name"]);
1649 NSString *theme(nil);
1651 #define testForTheme(format...) \
1652 if (theme == nil) { \
1653 NSString *path = [NSString stringWithFormat:format]; \
1654 if ([Manager_ fileExistsAtPath:path]) { \
1655 [Themes_ addObject:path]; \
1660 testForTheme(@"/Library/Themes/%@.theme", name)
1661 testForTheme(@"/Library/Themes/%@", name)
1662 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
1667 // Merge Info.plist {{{
1668 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1670 for (NSString *theme in Themes_)
1671 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
1672 for (NSString *key in [info allKeys])
1673 if ([Info_ objectForKey:key] == nil)
1674 [Info_ setObject:[info objectForKey:key] forKey:key];
1678 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
1679 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
1680 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
1683 // GraphicsServices {{{
1685 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
1689 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
1690 void *(*CGImageReadCreateWithFile)(NSString *, int);
1691 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
1692 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
1697 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
1698 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]);
1700 CFNotificationCenterAddObserver(
1701 CFNotificationCenterGetDarwinNotifyCenter(),
1702 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
1705 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
1706 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
1707 if (MediaPlayer != nil)
1710 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
1711 $MPVideoView = objc_getClass("MPVideoView");
1718 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
1720 memset(nl, 0, sizeof(nl));
1721 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
1722 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
1723 nl[2].n_un.n_name = (char *) "__UIKitBundle";
1724 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
1725 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
1728 nlset(_UIApplicationImageWithName, nl, 0);
1729 nlset(_UIImageWithNameInDomain, nl, 1);
1730 nlset(_UIKitBundle, nl, 2);
1731 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
1732 nlset(_UISharedImageNameGetIdentifier, nl, 4);
1734 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
1735 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
1736 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);