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]:WB:_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 MSMetaClassHook(UIImage)
122 MSClassHook(UINavigationBar)
123 MSClassHook(UIToolbar)
124 MSClassHook(UIStatusBarTimeItemView)
126 MSClassHook(CKBalloonView)
127 MSClassHook(CKMessageCell)
128 MSClassHook(CKTimestampView)
129 MSClassHook(CKTranscriptCell)
130 MSClassHook(CKTranscriptController)
131 MSClassHook(CKTranscriptHeaderView)
132 MSClassHook(CKTranscriptTableView)
134 MSClassHook(SBApplication)
135 MSClassHook(SBApplicationIcon)
136 MSClassHook(SBAwayView)
137 MSClassHook(SBBookmarkIcon)
138 MSClassHook(SBButtonBar)
139 MSClassHook(SBCalendarApplicationIcon)
140 MSClassHook(SBCalendarIconContentsView)
141 MSClassHook(SBDockIconListView)
143 MSClassHook(SBIconBadge)
144 MSClassHook(SBIconBadgeFactory)
145 MSClassHook(SBIconContentView)
146 MSClassHook(SBIconController)
147 MSClassHook(SBIconLabel)
148 MSClassHook(SBIconList)
149 MSClassHook(SBIconModel)
150 //MSClassHook(SBImageCache)
151 MSClassHook(SBSearchView)
152 MSClassHook(SBSearchTableViewCell)
153 MSClassHook(SBSlidingAlertDisplay)
154 MSClassHook(SBStatusBarContentsView)
155 MSClassHook(SBStatusBarController)
156 MSClassHook(SBStatusBarOperatorNameView)
157 MSClassHook(SBStatusBarTimeView)
158 MSClassHook(SBUIController)
159 MSClassHook(SBWallpaperView)
160 MSClassHook(SBWidgetApplicationIcon)
162 extern "C" void WKSetCurrentGraphicsContext(CGContextRef);
164 static struct MSFixClass { MSFixClass() {
165 $SBIcon = objc_getClass("SBIconView") ?: $SBIcon;
167 if ($SBIconList == nil)
168 $SBIconList = objc_getClass("SBIconListView");
169 if ($CKTranscriptController == nil)
170 $CKTranscriptController = objc_getClass("mSMSMessageTranscriptController");
174 static bool Four_($SBDockIconListView != nil);
176 @interface NSDictionary (WinterBoard)
177 - (UIColor *) wb$colorForKey:(NSString *)key;
178 - (BOOL) wb$boolForKey:(NSString *)key;
181 @implementation NSDictionary (WinterBoard)
183 - (UIColor *) wb$colorForKey:(NSString *)key {
184 NSString *value = [self objectForKey:key];
191 - (BOOL) wb$boolForKey:(NSString *)key {
192 if (NSString *value = [self objectForKey:key])
193 return [value boolValue];
199 static BOOL (*_GSFontGetUseLegacyFontMetrics)();
200 #define $GSFontGetUseLegacyFontMetrics() \
201 (_GSFontGetUseLegacyFontMetrics == NULL ? YES : _GSFontGetUseLegacyFontMetrics())
203 static bool Debug_ = false;
204 static bool UIDebug_ = false;
205 static bool Engineer_ = false;
206 static bool SummerBoard_ = false;
207 static bool SpringBoard_;
209 static UIImage *(*_UIApplicationImageWithName)(NSString *name);
210 static UIImage *(*_UIImageWithNameInDomain)(NSString *name, NSString *domain);
211 static NSBundle *(*_UIKitBundle)();
212 static bool (*_UIPackedImageTableGetIdentifierForName)(NSString *, int *);
213 static int (*_UISharedImageNameGetIdentifier)(NSString *);
215 static NSMutableDictionary *UIImages_ = [[NSMutableDictionary alloc] initWithCapacity:32];
216 static NSMutableDictionary *PathImages_ = [[NSMutableDictionary alloc] initWithCapacity:16];
217 static NSMutableDictionary *Cache_ = [[NSMutableDictionary alloc] initWithCapacity:64];
218 static NSMutableDictionary *Strings_ = [[NSMutableDictionary alloc] initWithCapacity:0];
219 static NSMutableDictionary *Bundles_ = [[NSMutableDictionary alloc] initWithCapacity:2];
221 static NSFileManager *Manager_;
222 static NSMutableArray *Themes_;
224 static NSDictionary *English_;
225 static NSMutableDictionary *Info_;
228 static NSMutableDictionary *Themed_ = [[NSMutableDictionary alloc] initWithCapacity:128];
230 static unsigned Scale_ = 0;
232 static unsigned $getScale$(NSString *path) {
233 NSString *name(path);
235 #define StripName(strip) \
236 if ([name hasSuffix:@ strip]) \
237 name = [name substringWithRange:NSMakeRange(0, [name length] - sizeof(strip) - 1)];
241 StripName("~iphone");
244 return [name hasSuffix:@"@2x"] ? 2 : 1;
247 static NSArray *$useScale$(NSArray *files, bool use = true) {
248 if (use && Scale_ == 0) {
249 UIScreen *screen([UIScreen mainScreen]);
250 if ([screen respondsToSelector:@selector(scale)])
251 Scale_ = [screen scale];
259 NSString *idiom(IsWild_ ? @"ipad" : @"iphone");
261 NSMutableArray *scaled([NSMutableArray arrayWithCapacity:([files count] * 4)]);
263 for (NSString *file in files) {
264 NSString *base([file stringByDeletingPathExtension]);
265 NSString *extension([file pathExtension]);
269 [scaled addObject:[NSString stringWithFormat:@"%@@2x~%@.%@", base, idiom, extension]];
271 [scaled addObject:[NSString stringWithFormat:@"%@@2x.%@", base, extension]];
274 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
276 // if (!IsWild_) <- support old themes
277 [scaled addObject:file];
278 } else if ([base hasSuffix: @"@2x"]) {
279 [scaled addObject:[NSString stringWithFormat:@"%@~iphone.%@", base, extension]];
280 [scaled addObject:file];
282 // XXX: this actually can't be used, as the person loading the file doesn't realize that the @2x changed
283 /*NSString *rest([base substringWithRange:NSMakeRange(0, [base length] - 3)]);
284 [scaled addObject:[NSString stringWithFormat:@"%@~iphone.%@", rest, extension]];
285 [scaled addObject:[rest stringByAppendingPathExtension:extension]];*/
287 // XXX: this code isn't really complete
289 [scaled addObject:file];
291 if ([base hasSuffix:@"~iphone"])
292 [scaled addObject:[[base substringWithRange:NSMakeRange(0, [base length] - 7)] stringByAppendingPathExtension:extension]];
299 static NSString *$getTheme$(NSArray *files, NSArray *themes = Themes_) {
300 // XXX: this is not reasonable; OMG
303 @synchronized (Themed_) {
304 if (NSString *path = [Themed_ objectForKey:key])
305 return reinterpret_cast<id>(path) == [NSNull null] ? nil : path;
309 NSLog(@"WB:Debug: %@", [files description]);
313 for (NSString *theme in Themes_)
314 for (NSString *file in files) {
315 path = [NSString stringWithFormat:@"%@/%@", theme, file];
316 if ([Manager_ fileExistsAtPath:path])
323 @synchronized (Themed_) {
324 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:key];
330 // $pathForFile$inBundle$() {{{
331 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool ui) {
332 NSString *identifier = [bundle bundleIdentifier];
333 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
335 if (identifier != nil)
336 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
337 if (NSString *folder = [[bundle bundlePath] lastPathComponent]) {
338 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
339 NSString *base([folder stringByDeletingPathExtension]);
340 if ([base hasSuffix:@"~iphone"])
341 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 7)], [folder pathExtension], file]];
344 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
346 #define remapResourceName(oldname, newname) \
347 else if ([file isEqualToString:(oldname)]) \
348 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
350 bool summer(SpringBoard_ && SummerBoard_);
352 if (identifier == nil);
353 else if ([identifier isEqualToString:@"com.apple.chatkit"])
354 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
355 else if ([identifier isEqualToString:@"com.apple.calculator"])
356 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
358 remapResourceName(@"FSO_BG.png", @"StatusBar")
359 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
360 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
362 [names addObject:[NSString stringWithFormat:@"Fallback/%@", file]];
364 if (NSString *path = $getTheme$($useScale$(names, ui)))
371 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
372 NSString *identifier = [self bundleIdentifier];
373 NSString *path = [self path];
374 NSString *folder = [path lastPathComponent];
375 NSString *dname = [self displayName];
376 NSString *didentifier = [self displayIdentifier];
379 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
381 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
383 /* XXX: I might need to keep this for backwards compatibility
384 if (identifier != nil)
385 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
387 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
389 #define testForIcon(Name) \
390 if (NSString *name = Name) \
391 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
393 if (![didentifier isEqualToString:identifier])
394 testForIcon(didentifier);
396 testForIcon(identifier);
399 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
402 if (didentifier != nil) {
403 testForIcon([English_ objectForKey:didentifier]);
405 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
406 if ([parts count] != 1)
407 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
408 testForIcon([english objectForKey:[parts lastObject]]);
411 if (NSString *path = $getTheme$(names))
417 // -[NSBundle wb$bundleWithFile] {{{
418 @interface NSBundle (WinterBoard)
419 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
422 @implementation NSBundle (WinterBoard)
424 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
425 path = [path stringByDeletingLastPathComponent];
426 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
429 NSBundle *bundle([Bundles_ objectForKey:path]);
430 if (reinterpret_cast<id>(bundle) == [NSNull null])
432 else if (bundle == nil) {
433 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
434 bundle = [NSBundle bundleWithPath:path];
436 bundle = [NSBundle wb$bundleWithFile:path];
438 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
439 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
447 // -[NSString wb$themedPath] {{{
448 @interface NSString (WinterBoard)
449 - (NSString *) wb$themedPath;
452 @implementation NSString (WinterBoard)
454 - (NSString *) wb$themedPath {
455 if ([self hasPrefix:@"/Library/Themes/"])
459 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
461 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
462 NSString *file([self stringByResolvingSymlinksInPath]);
463 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
464 if ([file hasPrefix:prefix]) {
465 NSUInteger length([prefix length]);
466 if (length != [file length])
467 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
478 void WBLogRect(const char *tag, struct CGRect rect) {
479 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
482 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
483 CGRect frame([view frame]);
484 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]);
486 for (UIView *child in [view subviews])
487 WBLogHierarchy(child, index++, indent + 1);
490 UIImage *$cacheForImage$(UIImage *image) {
491 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
492 CGRect rect = {CGPointMake(1, 1), [image size]};
493 CGSize size = {rect.size.width + 2, rect.size.height + 2};
495 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
496 CGColorSpaceRelease(space);
498 CGContextDrawImage(context, rect, [image CGImage]);
499 CGImageRef ref(CGBitmapContextCreateImage(context));
500 CGContextRelease(context);
502 UIImage *cache([UIImage imageWithCGImage:ref]);
508 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
509 //if ([name isEqualToString:@"icons"]) return nil;
510 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
513 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
514 NSString *key([icon displayIdentifier]);
516 if (UIImage *image = [icon icon]) {
517 CGSize size = [image size];
518 if (size.width != 59 || size.height != 60) {
519 UIImage *cache($cacheForImage$(image));
520 [Cache_ setObject:cache forKey:key];
525 _SBIconModel$cacheImageForIcon$(self, sel, icon);
528 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
529 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
530 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
532 NSString *key([icon displayIdentifier]);
534 if (UIImage *image = [icon icon]) {
535 CGSize size = [image size];
536 if (size.width != 59 || size.height != 60) {
537 UIImage *cache($cacheForImage$(image));
538 [Cache_ setObject:cache forKey:key];
544 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
545 NSString *key([icon displayIdentifier]);
546 if (UIImage *image = [Cache_ objectForKey:key])
549 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
552 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
554 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
555 NSString *key([icon displayIdentifier]);
556 if (UIImage *image = [Cache_ objectForKey:key])
559 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
562 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
563 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
564 [self setBackgroundColor:[UIColor clearColor]];
565 for (UIView *child in [self subviews])
566 [child setBackgroundColor:[UIColor clearColor]];
570 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
571 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
572 [self setBackgroundColor:[UIColor clearColor]];
576 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
577 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
578 float inset([self edgeInset]);
579 [[UIColor clearColor] set];
580 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
581 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
584 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
585 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
586 if (NSString *path = $pathForIcon$([self application]))
587 return [UIImage imageWithContentsOfFile:path];
588 return _SBApplicationIcon$icon(self, sel);
591 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
593 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
594 if (IsWild_ && false) // XXX: delete this code, it should not be supported
595 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
596 return [UIImage imageWithContentsOfFile:path72];
597 if (NSString *path = $pathForIcon$([self application]))
598 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
600 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
601 width = [$SBIcon defaultIconImageSize].width;
604 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
607 return _SBApplicationIcon$generateIconImage$(self, sel, type);
610 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
612 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
613 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
614 return [UIImage imageWithContentsOfFile:path];
615 return _SBWidgetApplicationIcon$icon(self, sel);
618 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
620 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
621 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
622 return [UIImage imageWithContentsOfFile:path];
623 return _SBBookmarkIcon$icon(self, sel);
626 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
627 if (NSString *path = $pathForIcon$(self))
629 return _SBApplication$pathForIcon(self, sel);
632 static UIImage *CachedImageAtPath(NSString *path) {
633 path = [path stringByResolvingSymlinksInPath];
634 UIImage *image = [PathImages_ objectForKey:path];
636 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
637 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
639 image = [image autorelease];
640 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
644 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
645 NSBundle *bundle = [NSBundle mainBundle];
647 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
648 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
649 return CachedImageAtPath(path);
650 return __UIApplicationImageWithName(name);
653 #define WBDelegate(delegate) \
654 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
656 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
657 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
659 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
663 - (void) forwardInvocation:(NSInvocation*)inv { \
664 SEL sel = [inv selector]; \
665 if ([delegate respondsToSelector:sel]) \
666 [inv invokeWithTarget:delegate]; \
668 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
671 // %hook -[NSBundle pathForResource:ofType:] {{{
672 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
673 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
675 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
676 if (NSString *path = $pathForFile$inBundle$(file, self, false))
678 return MSOldCall(resource, type);
682 static void $drawLabel$(NSString *label, CGRect rect, NSString *style, NSString *custom) {
683 bool ellipsis(false);
684 float max = rect.size.width - 11, width;
686 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
689 size_t length([label length]);
690 float spacing((width - max) / (length - 1));
692 if (spacing > 1.25) {
694 label = [label substringToIndex:(length - 1)];
698 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
702 label = [label stringByAppendingString:@"..."];
705 style = [style stringByAppendingString:custom];
707 CGSize size = [label sizeWithStyle:style forWidth:rect.size.width];
708 [label drawAtPoint:CGPointMake((rect.size.width - size.width) / 2 + rect.origin.x, rect.origin.y) withStyle:style];
711 static struct WBStringDrawingState {
712 WBStringDrawingState *next_;
716 } *stringDrawingState_;
718 MSInstanceMessageHook6(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode,letterSpacing,includeEmoji, CGPoint, point, float, width, UIFont *, font, UILineBreakMode, mode, float, spacing, BOOL, emoji) {
719 //NSLog(@"XXX: @\"%@\" %g", self, spacing);
721 WBStringDrawingState *state(stringDrawingState_);
723 return MSOldCall(point, width, font, mode, spacing, emoji);
725 if (--state->count_ == 0)
726 stringDrawingState_ = state->next_;
727 if (state->info_ == nil)
728 return MSOldCall(point, width, font, mode, spacing, emoji);
730 NSString *info([Info_ objectForKey:state->info_]);
732 return MSOldCall(point, width, font, mode, spacing, emoji);
734 NSString *base(state->base_ ?: @"");
735 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
736 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], extra, base, info]];
740 extern "C" NSString *NSStringFromCGRect(CGRect rect);
742 MSInstanceMessageHook7(CGSize, NSString, _drawInRect,withFont,lineBreakMode,alignment,lineSpacing,includeEmoji,truncationRect, CGRect, rect, UIFont *, font, UILineBreakMode, mode, UITextAlignment, alignment, float, spacing, BOOL, emoji, CGRect, truncation) {
743 //NSLog(@"XXX: &\"%@\" %@ \"%@\" %u %u %g %u %@", self, NSStringFromCGRect(rect), font, mode, alignment, spacing, emoji, NSStringFromCGRect(truncation));
745 WBStringDrawingState *state(stringDrawingState_);
747 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
749 if (--state->count_ == 0)
750 stringDrawingState_ = state->next_;
751 if (state->info_ == nil)
752 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
754 NSString *info([Info_ objectForKey:state->info_]);
756 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
761 case UITextAlignmentLeft:
764 case UITextAlignmentCenter:
765 textAlign = @"center";
767 case UITextAlignmentRight:
768 textAlign = @"right";
772 NSString *base(state->base_ ?: @"");
773 NSString *extra([NSString stringWithFormat:@"text-align: %@", textAlign]);
776 $drawLabel$(self, rect, [NSString stringWithFormat:@"%@;%@", [font markupDescription], base], info);
778 [self drawInRect:rect withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], extra, base, info]];
783 MSInstanceMessageHook4(CGSize, NSString, sizeWithFont,forWidth,lineBreakMode,letterSpacing, UIFont *, font, float, width, UILineBreakMode, mode, float, spacing) {
784 //NSLog(@"XXX: #\"%@\" \"%@\" %g %u %g", self, font, width, mode, spacing);
786 WBStringDrawingState *state(stringDrawingState_);
788 return MSOldCall(font, width, mode, spacing);
790 if (--state->count_ == 0)
791 stringDrawingState_ = state->next_;
792 if (state->info_ == nil)
793 return MSOldCall(font, width, mode, spacing);
795 NSString *info([Info_ objectForKey:state->info_]);
797 return MSOldCall(font, width, mode, spacing);
799 NSString *base(state->base_ ?: @"");
800 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
801 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], extra, base, info] forWidth:width];
804 MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) {
805 //NSLog(@"XXX: ?\"%@\"", self);
807 WBStringDrawingState *state(stringDrawingState_);
809 return MSOldCall(font);
811 if (--state->count_ == 0)
812 stringDrawingState_ = state->next_;
813 if (state->info_ == nil)
814 return MSOldCall(font);
816 NSString *info([Info_ objectForKey:state->info_]);
818 return MSOldCall(font);
820 NSString *base(state->base_ ?: @"");
821 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info] forWidth:65535];
824 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
825 WBStringDrawingState badgeState = {NULL, 1, @""
829 stringDrawingState_ = &badgeState;
831 UIImage *image(MSOldCall(text));
833 stringDrawingState_ = NULL;
837 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
838 WBStringDrawingState dayState = {NULL, 2, @""
840 // XXX: this is only correct on an iPod dock
841 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
842 , @"CalendarIconDayStyle"};
844 WBStringDrawingState sizeState = {&dayState, 7, nil, nil};
846 WBStringDrawingState dateState = {&sizeState, 2, @""
848 , @"CalendarIconDateStyle"};
850 stringDrawingState_ = &dateState;
852 UIImage *image(MSOldCall(type));
854 stringDrawingState_ = NULL;
858 MSInstanceMessageHook1(UIImage *, UIStatusBarTimeItemView, contentsImageForStyle, int, style) {
859 WBStringDrawingState timeState = {NULL, 0, @""
863 stringDrawingState_ = &timeState;
865 UIImage *image(MSOldCall(style));
867 stringDrawingState_ = NULL;
871 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
872 NSBundle *bundle([NSBundle mainBundle]);
874 CFLocaleRef locale(CFLocaleCopyCurrent());
875 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
878 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
880 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
881 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
882 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
883 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
887 CFRelease(formatter);
889 NSString *datestyle([@""
890 "font-family: Helvetica; "
891 "font-weight: bold; "
894 "" stringByAppendingString:(IsWild_
895 ? @"font-size: 54px; "
896 : @"font-size: 39px; "
899 NSString *daystyle([@""
900 "font-family: Helvetica; "
901 "font-weight: bold; "
903 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
904 "" stringByAppendingString:(IsWild_
905 ? @"font-size: 11px; "
906 : @"font-size: 9px; "
909 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
910 datestyle = [datestyle stringByAppendingString:style];
911 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
912 daystyle = [daystyle stringByAppendingString:style];
914 float width([self bounds].size.width);
916 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
917 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
919 unsigned base0(IsWild_ ? 89 : 70);
920 if ($GSFontGetUseLegacyFontMetrics())
922 unsigned base1(IsWild_ ? 18 : 16);
929 [(NSString *)date drawAtPoint:CGPointMake(
930 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
931 ) withStyle:datestyle];
933 [(NSString *)day drawAtPoint:CGPointMake(
934 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
935 ) withStyle:daystyle];
941 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
942 void $setBarStyle$_(NSString *name, int &style) {
944 NSLog(@"WB:Debug:%@Style:%d", name, style);
945 NSNumber *number = nil;
947 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
949 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
951 style = [number intValue];
953 NSLog(@"WB:Debug:%@Style=%d", name, style);
957 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
958 $setBarStyle$_(@"Toolbar", style);
959 return MSOldCall(style);
962 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
963 $setBarStyle$_(@"NavigationBar", style);
964 return MSOldCall(style);
968 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
969 [[self superview] setBackgroundColor:[UIColor clearColor]];
970 _SBButtonBar$didMoveToSuperview(self, sel);
973 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
974 [[self superview] setBackgroundColor:[UIColor clearColor]];
975 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
978 static NSArray *Wallpapers_;
979 static bool Papered_;
981 static bool SMSBackgrounded_;
982 static NSString *WallpaperFile_;
983 static UIImageView *WallpaperImage_;
984 static UIWebDocumentView *WallpaperPage_;
985 static NSURL *WallpaperURL_;
987 #define _release(object) \
988 do if (object != nil) { \
993 static UIImage *$getImage$(NSString *path) {
994 UIImage *image([UIImage imageWithContentsOfFile:path]);
996 unsigned scale($getScale$(path));
997 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
998 [image setScale:scale];
1003 static UIImage *$getDefaultDesktopImage$() {
1004 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
1005 return $getImage$(path);
1009 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
1010 return $getDefaultDesktopImage$() ?: MSOldCall();
1013 MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
1014 return $getDefaultDesktopImage$() ?: MSOldCall();
1017 MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
1018 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
1019 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
1020 if (UIImage *image = $getDefaultDesktopImage$()) {
1021 [self setImage:image];
1031 // %hook -[SBUIController init] {{{
1032 MSInstanceMessageHook0(id, SBUIController, init) {
1037 NSString *paper($getTheme$(Wallpapers_));
1039 paper = [paper stringByDeletingLastPathComponent];
1043 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
1044 char *machine = new char[size];
1046 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
1047 perror("sysctlbyname(\"hw.machine\", ?)");
1052 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
1056 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
1059 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
1060 if (&_wallpaperView != NULL) {
1061 [_wallpaperView removeFromSuperview];
1062 [_wallpaperView release];
1063 _wallpaperView = nil;
1067 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
1068 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
1071 if (&_contentLayer != NULL)
1072 player = &_contentLayer;
1073 else if (&_contentView != NULL)
1074 player = &_contentView;
1077 UIView *layer(player == NULL ? nil : *player);
1079 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
1080 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
1081 [window setContentView:content];
1083 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
1084 [window setBackgroundColor:[_window backgroundColor]];
1085 [_window setBackgroundColor:[UIColor clearColor]];
1087 [window setLevel:-1000];
1088 [window setHidden:NO];
1090 /*if (player != NULL)
1091 *player = content;*/
1093 [content setBackgroundColor:[layer backgroundColor]];
1094 [layer setBackgroundColor:[UIColor clearColor]];
1097 if (!SummerBoard_ || !IsWild_)
1100 CGRect bounds([content bounds]);
1101 bounds.origin.y = -30;
1102 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
1103 [content addSubview:indirect];
1104 [indirect zoomToScale:2.4];
1107 _release(WallpaperFile_);
1108 _release(WallpaperImage_);
1109 _release(WallpaperPage_);
1110 _release(WallpaperURL_);
1113 NSArray *themes([NSArray arrayWithObject:paper]);
1115 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1119 static AVController *controller_(nil);
1120 if (controller_ == nil) {
1121 AVQueue *queue([AVQueue avQueue]);
1122 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1125 AVQueue *queue([controller_ queue]);
1127 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1128 [controller_ setLayer:[video _layer]];
1130 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1131 [queue appendItem:item error:&error];
1133 [controller_ play:&error];
1134 #elif UseMPMoviePlayerController
1135 NSURL *url([NSURL fileURLWithPath:path]);
1136 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1137 controller.movieControlMode = MPMovieControlModeHidden;
1140 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1141 [video setMovieWithPath:path];
1142 [video setRepeatMode:1];
1143 [video setRepeatGap:-1];
1144 [video playFromBeginning];;
1147 [indirect addSubview:video];
1150 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1151 if (UIImage *image = $getImage$(path)) {
1152 WallpaperFile_ = [path retain];
1153 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1154 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1155 [WallpaperImage_ setAlpha:[number floatValue]];
1156 [indirect addSubview:WallpaperImage_];
1160 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1161 CGRect bounds = [indirect bounds];
1163 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1164 [view setAutoresizes:true];
1166 WallpaperPage_ = [view retain];
1167 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1169 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1171 [view setBackgroundColor:[UIColor clearColor]];
1172 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1173 [view setDrawsBackground:NO];
1174 [[view webView] setDrawsBackground:NO];
1176 [indirect addSubview:view];
1180 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1181 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1182 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1183 if ([Manager_ fileExistsAtPath:html]) {
1184 CGRect bounds = [indirect bounds];
1186 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1187 [view setAutoresizes:true];
1189 NSURL *url = [NSURL fileURLWithPath:html];
1190 [view loadRequest:[NSURLRequest requestWithURL:url]];
1192 [view setBackgroundColor:[UIColor clearColor]];
1193 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1194 [view setDrawsBackground:NO];
1195 [[view webView] setDrawsBackground:NO];
1197 [indirect addSubview:view];
1205 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1206 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1207 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1209 if (path != nil && _backgroundView != nil)
1212 _SBAwayView$updateDesktopImage$(self, sel, image);
1215 CGRect bounds = [self bounds];
1217 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1218 [view setAutoresizes:true];
1220 if (WallpaperPage_ != nil)
1221 [WallpaperPage_ release];
1222 WallpaperPage_ = [view retain];
1224 if (WallpaperURL_ != nil)
1225 [WallpaperURL_ release];
1226 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1228 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1230 [[view webView] setDrawsBackground:false];
1231 [view setBackgroundColor:[UIColor clearColor]];
1233 [self insertSubview:view aboveSubview:_backgroundView];
1237 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1238 extern "C" CGColorRef CGGStateGetFillColor(void *);
1239 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1240 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1242 /* WBTimeLabel {{{ */
1243 @interface WBTimeLabel : NSProxy {
1245 _transient SBStatusBarTimeView *view_;
1248 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1252 @implementation WBTimeLabel
1259 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1260 time_ = [time retain];
1265 - (NSString *) description {
1271 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1272 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1273 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1275 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1276 "font-family: Helvetica; "
1277 "font-weight: bold; "
1280 "%@", _mode ? @"white" : @"black", custom]];
1285 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1290 /* WBBadgeLabel {{{ */
1291 @interface WBBadgeLabel : NSProxy {
1295 - (id) initWithBadge:(NSString *)badge;
1296 - (NSString *) description;
1300 @implementation WBBadgeLabel
1307 - (id) initWithBadge:(NSString *)badge {
1308 badge_ = [badge retain];
1312 - (NSString *) description {
1313 return [badge_ description];
1318 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1319 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1320 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1321 "font-family: Helvetica; "
1322 "font-weight: bold; "
1330 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1337 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1338 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1339 alpha = [number floatValue];
1340 return MSOldCall(alpha);
1343 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1344 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1345 alpha = [number floatValue];
1346 return MSOldCall(alpha);
1349 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1350 if ((self = MSOldCall()) != nil) {
1351 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1352 // XXX: note: this is overridden above, which is silly
1353 float alpha([number floatValue]);
1354 if ([self respondsToSelector:@selector(setIconImageAlpha:)])
1355 [self setIconImageAlpha:alpha];
1356 if ([self respondsToSelector:@selector(setIconLabelAlpha:)])
1357 [self setIconLabelAlpha:alpha];
1358 if ([self respondsToSelector:@selector(setAlpha:)])
1359 [self setAlpha:alpha];
1364 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1365 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1366 alpha = [number floatValue];
1367 return MSOldCall(alpha);
1371 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1372 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1373 id &_badge(MSHookIvar<id>(self, "_badge"));
1375 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1380 void SBStatusBarController$setStatusBarMode(int &mode) {
1382 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1383 if (mode < 100) // 104:hidden 105:glowing
1384 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1385 mode = [number intValue];
1388 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1389 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1390 SBStatusBarController$setStatusBarMode(mode);
1391 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1394 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1395 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1396 SBStatusBarController$setStatusBarMode(mode);
1397 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1400 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) {
1401 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1402 SBStatusBarController$setStatusBarMode(mode);
1403 //NSLog(@"mode=%u", mode);
1404 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1407 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1408 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1409 mode = [number intValue];
1410 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1413 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1414 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1416 NSLog(@"operatorNameStyle= %@", style);
1417 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1418 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1422 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1424 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1425 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1428 // XXX: replace this with [SBStatusBarTimeView tile]
1429 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1430 id &_time(MSHookIvar<id>(self, "_time"));
1431 if (_time != nil && [_time class] != [WBTimeLabel class])
1432 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1433 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1436 @interface UIView (WinterBoard)
1437 - (bool) wb$isWBImageView;
1438 - (void) wb$logHierarchy;
1439 - (void) wb$setBackgroundColor:(UIColor *)color;
1442 @implementation UIView (WinterBoard)
1444 - (bool) wb$isWBImageView {
1448 - (void) wb$logHierarchy {
1449 WBLogHierarchy(self);
1452 - (void) wb$setBackgroundColor:(UIColor *)color {
1453 [self setBackgroundColor:color];
1454 for (UIView *child in [self subviews])
1455 [child wb$setBackgroundColor:color];
1460 @interface WBImageView : UIImageView {
1463 - (bool) wb$isWBImageView;
1464 - (void) wb$updateFrame;
1467 @implementation WBImageView
1469 - (bool) wb$isWBImageView {
1473 - (void) wb$updateFrame {
1474 CGRect frame([self frame]);
1477 for (UIView *view(self); ; ) {
1478 view = [view superview];
1481 frame.origin.y -= [view frame].origin.y;
1484 [self setFrame:frame];
1489 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1490 NSArray *subviews([self subviews]);
1491 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1492 if (view != nil && [view wb$isWBImageView])
1493 [view wb$updateFrame];
1494 _SBIconList$setFrame$(self, sel, frame);
1497 static void $addPerPageView$(unsigned i, UIView *list) {
1498 NSString *path($getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]]));
1502 NSArray *subviews([list subviews]);
1504 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1505 if (view == nil || ![view wb$isWBImageView]) {
1506 view = [[[WBImageView alloc] init] autorelease];
1507 [list insertSubview:view atIndex:0];
1510 UIImage *image([UIImage imageWithContentsOfFile:path]);
1512 CGRect frame([view frame]);
1513 frame.size = [image size];
1514 [view setFrame:frame];
1516 [view setImage:image];
1517 [view wb$updateFrame];
1520 static void $addPerPageViews$(NSArray *lists) {
1521 for (unsigned i(0), e([lists count]); i != e; ++i)
1522 $addPerPageView$(i, [lists objectAtIndex:i]);
1525 MSInstanceMessageHook0(void, SBIconController, updateNumberOfRootIconLists) {
1526 NSArray *&_rootIconLists(MSHookIvar<NSArray *>(self, "_rootIconLists"));
1527 $addPerPageViews$(_rootIconLists);
1531 MSInstanceMessageHook0(void, SBIconContentView, layoutSubviews) {
1534 if (SBIconController *controller = [$SBIconController sharedInstance]) {
1535 UIView *&_dockContainerView(MSHookIvar<UIView *>(controller, "_dockContainerView"));
1536 if (&_dockContainerView != NULL)
1537 [[_dockContainerView superview] bringSubviewToFront:_dockContainerView];
1541 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1542 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1543 $addPerPageViews$([_iconModel iconLists]);
1544 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1547 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1548 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1550 [self setClipsToBounds:NO];
1554 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1555 static bool gssc(false);
1557 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1558 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1561 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1562 [Info_ setObject:[NSNumber numberWithBool:(
1564 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1565 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1566 )] forKey:@"UndockedIconLabels"];
1569 id &_label(MSHookIvar<id>(self, "_label"));
1570 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1573 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1574 [_label setInDock:docked];
1576 _SBIconLabel$setInDock$(self, sel, docked);
1577 [self setNeedsDisplay];
1580 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1581 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1584 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1585 _SBDockIconListView$setFrame$(self, sel, frame);
1588 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1589 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1590 NSString *identifier = [self bundleIdentifier];
1591 NSLocale *locale = [NSLocale currentLocale];
1592 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1594 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1595 NSString *file = table == nil ? @"Localizable" : table;
1596 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1597 NSDictionary *strings;
1598 if ((strings = [Strings_ objectForKey:name]) != nil) {
1599 if (static_cast<id>(strings) != [NSNull null]) strings:
1600 if (NSString *value = [strings objectForKey:key])
1602 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1605 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1606 [Strings_ setObject:[strings autorelease] forKey:name];
1610 [Strings_ setObject:[NSNull null] forKey:name];
1611 return MSOldCall(key, value, table);
1614 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1615 MSClassHook(WebCoreFrameBridge)
1617 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1620 void **core(reinterpret_cast<void **>([node _node]));
1621 if (core == NULL || core[6] == NULL)
1623 return MSOldCall(node, width);
1627 MSInstanceMessage1(void, SBIconLabel, drawRect, CGRect, rect) {
1628 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1631 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1632 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1634 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1636 NSString *style = [NSString stringWithFormat:@""
1637 "font-family: Helvetica; "
1638 "font-weight: bold; "
1640 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1641 ? @"font-size: 12px; "
1642 : @"font-size: 11px; "
1646 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1648 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1650 NSString *custom([Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")]);
1652 $drawLabel$(label, [self bounds], style, custom);
1655 MSInstanceMessage0(CGImageRef, SBIconLabel, buildLabelImage) {
1656 bool docked((MSHookIvar<unsigned>(self, "_inDock") & 0x2) != 0);
1658 WBStringDrawingState labelState = {NULL, 0, @""
1660 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1662 stringDrawingState_ = &labelState;
1665 CGImageRef image(MSOldCall());
1668 stringDrawingState_ = NULL;
1673 MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1674 if ((self = MSOldCall(frame, delegate)) != nil) {
1675 [self setBackgroundColor:[UIColor clearColor]];
1679 MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1680 return SMSBackgrounded_ ? NO : MSOldCall();
1683 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1684 [self wb$setBackgroundColor:[UIColor clearColor]];
1688 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1690 [balloon setBackgroundColor:[UIColor clearColor]];
1693 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1694 MSOldCall([UIColor clearColor]);
1695 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1699 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1700 if ((self = MSOldCall(style, reuse)) != nil) {
1701 [self setBackgroundColor:[UIColor clearColor]];
1702 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1707 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1708 if ((self = MSOldCall(style, reuse)) != nil) {
1709 [self setBackgroundColor:[UIColor clearColor]];
1710 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1714 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1715 if ((self = MSOldCall(style, reuse)) != nil) {
1716 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1717 [_label setBackgroundColor:[UIColor clearColor]];
1721 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1722 MSOldCall(UITableViewCellSeparatorStyleNone);
1725 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1726 if ((self = MSOldCall(frame, style)) != nil) {
1727 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1731 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1734 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1735 if (UIImage *image = $getImage$(path)) {
1736 SMSBackgrounded_ = true;
1738 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1739 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1741 if (&_transcriptTable != NULL)
1742 table = _transcriptTable;
1743 else if (&_transcriptLayer != NULL)
1744 table = _transcriptLayer;
1748 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1749 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1752 [placard insertSubview:background atIndex:0];
1754 [table setBackgroundColor:[UIColor clearColor]];
1755 [placard insertSubview:background belowSubview:table];
1761 // %hook _UIImageWithName() {{{
1762 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1764 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1771 if (_UIPackedImageTableGetIdentifierForName != NULL)
1772 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1773 else if (_UISharedImageNameGetIdentifier != NULL) {
1774 identifier = _UISharedImageNameGetIdentifier(name);
1775 packed = identifier != -1;
1782 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1785 return __UIImageWithName(name);
1787 NSNumber *key([NSNumber numberWithInt:identifier]);
1788 UIImage *image([UIImages_ objectForKey:key]);
1790 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1791 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1792 image = $getImage$(path);
1793 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1797 image = __UIImageWithName(name);
1800 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1801 if (![Manager_ fileExistsAtPath:path])
1802 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1809 // %hook _UIImageWithNameInDomain() {{{
1810 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1811 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1812 UIImage *image([PathImages_ objectForKey:key]);
1814 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1816 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1817 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1818 image = $getImage$(path);
1819 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1820 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1824 // %hook GSFontCreateWithName() {{{
1825 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1827 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1828 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1829 name = [font UTF8String];
1830 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1831 // size *= [scale floatValue];
1832 return _GSFontCreateWithName(name, traits, size);
1836 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1837 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1839 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1841 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1843 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1844 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1846 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1849 NSString *path = [NSString stringWithUTF8String:a1];
1850 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1851 NSString *file = [path substringFromIndex:31];
1852 for (NSString *theme in Themes_) {
1853 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1854 if ([Manager_ fileExistsAtPath:path]) {
1855 strcpy(a1, [path UTF8String]);
1864 static void ChangeWallpaper(
1865 CFNotificationCenterRef center,
1869 CFDictionaryRef info
1872 NSLog(@"WB:Debug:ChangeWallpaper!");
1875 if (WallpaperFile_ != nil) {
1876 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1878 image = [image autorelease];
1881 if (WallpaperImage_ != nil)
1882 [WallpaperImage_ setImage:image];
1883 if (WallpaperPage_ != nil)
1884 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1888 #define WBRename(name, sel, imp) \
1889 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
1891 template <typename Type_>
1892 static void msset(Type_ &function, MSImageRef image, const char *name) {
1893 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1896 template <typename Type_>
1897 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1898 struct nlist &name(nl[index]);
1899 uintptr_t value(name.n_value);
1900 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1901 value |= 0x00000001;
1902 function = reinterpret_cast<Type_>(value);
1905 template <typename Type_>
1906 static void dlset(Type_ &function, const char *name) {
1907 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1910 // %hook CGImageReadCreateWithFile() {{{
1911 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1913 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1914 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1915 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1921 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
1922 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1923 if (style == nil || [style length] == 0)
1924 style = @"font-family: Helvetica; font-size: 12px";
1925 //NSLog(@"XXX:draw(%@)", [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
1926 return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
1929 static void NSString$drawInRect$withStyle$(NSString *self, SEL _cmd, CGRect rect, NSString *style) {
1930 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1931 if (style == nil || [style length] == 0)
1932 style = @"font-family: Helvetica; font-size: 12px";
1933 return [[WBMarkup sharedMarkup] drawString:self inRect:rect withStyle:style];
1936 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
1937 if (style == nil || [style length] == 0)
1938 style = @"font-family: Helvetica; font-size: 12px";
1939 //NSLog(@"XXX:size(%@)", [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
1940 return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width];
1943 static void SBInitialize() {
1944 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
1945 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v28@0:4{CGRect={CGSize=ff}{CGSize=ff}}8@24");
1946 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
1949 WBRename(SBApplication, pathForIcon, pathForIcon);
1950 WBRename(SBApplicationIcon, icon, icon);
1951 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1954 WBRename(SBBookmarkIcon, icon, icon);
1955 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1956 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1957 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1958 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
1960 WBRename(SBWidgetApplicationIcon, icon, icon);
1962 WBRename(SBDockIconListView, setFrame:, setFrame$);
1963 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
1965 if (kCFCoreFoundationVersionNumber < 600 || SummerBoard_)
1966 WBRename(SBIconLabel, drawRect:, drawRect$);
1968 WBRename(SBIconLabel, buildLabelImage, buildLabelImage);
1970 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
1971 WBRename(SBIconLabel, setInDock:, setInDock$);
1973 WBRename(SBIconList, setFrame:, setFrame$);
1975 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
1976 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
1977 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
1978 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
1980 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
1981 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
1982 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
1984 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
1986 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
1987 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
1988 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
1989 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
1990 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
1991 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
1992 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
1993 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
1994 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
1997 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
2001 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2003 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
2004 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
2006 Manager_ = [[NSFileManager defaultManager] retain];
2007 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
2009 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
2011 // Load Settings.plist {{{
2012 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
2013 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
2014 SummerBoard_ = [value boolValue];
2016 SummerBoard_ = true;
2018 if (NSNumber *value = [settings objectForKey:@"Debug"])
2019 Debug_ = [value boolValue];
2020 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
2021 UIDebug_ = [value boolValue];
2023 NSArray *themes([settings objectForKey:@"Themes"]);
2025 if (NSString *theme = [settings objectForKey:@"Theme"])
2026 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
2028 [NSNumber numberWithBool:true], @"Active",
2032 for (NSDictionary *theme in themes) {
2033 NSNumber *active([theme objectForKey:@"Active"]);
2034 if (![active boolValue])
2037 NSString *name([theme objectForKey:@"Name"]);
2041 NSString *theme(nil);
2043 #define testForTheme(format...) \
2044 if (theme == nil) { \
2045 NSString *path = [NSString stringWithFormat:format]; \
2046 if ([Manager_ fileExistsAtPath:path]) { \
2047 [Themes_ addObject:path]; \
2052 testForTheme(@"/Library/Themes/%@.theme", name)
2053 testForTheme(@"/Library/Themes/%@", name)
2054 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
2059 // Merge Info.plist {{{
2060 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2062 for (NSString *theme in Themes_)
2063 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
2064 for (NSString *key in [info allKeys])
2065 if ([Info_ objectForKey:key] == nil)
2066 [Info_ setObject:[info objectForKey:key] forKey:key];
2070 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
2071 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
2072 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
2075 // GraphicsServices {{{
2077 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
2081 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
2082 void *(*CGImageReadCreateWithFile)(NSString *, int);
2083 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
2084 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
2089 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
2090 Papered_ = $getTheme$(Wallpapers_) != nil;
2091 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
2093 CFNotificationCenterAddObserver(
2094 CFNotificationCenterGetDarwinNotifyCenter(),
2095 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
2098 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
2099 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
2100 if (MediaPlayer != nil)
2103 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
2104 $MPVideoView = objc_getClass("MPVideoView");
2111 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
2113 memset(nl, 0, sizeof(nl));
2114 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
2115 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
2116 nl[2].n_un.n_name = (char *) "__UIKitBundle";
2117 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
2118 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
2121 nlset(_UIApplicationImageWithName, nl, 0);
2122 nlset(_UIImageWithNameInDomain, nl, 1);
2123 nlset(_UIKitBundle, nl, 2);
2124 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
2125 nlset(_UISharedImageNameGetIdentifier, nl, 4);
2127 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
2128 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
2129 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
2133 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
2134 NSError *error(nil);
2135 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
2136 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
2138 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);