1 /* WinterBoard - Theme Manager for the iPhone
2 * Copyright (C) 2008-2014 Jay Freeman (saurik)
5 /* GNU Lesser General Public License, Version 3 {{{ */
7 * WinterBoard is free software: you can redistribute it and/or modify it under
8 * the terms of the GNU Lesser General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
12 * WinterBoard is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 * License for more details.
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with WinterBoard. If not, see <http://www.gnu.org/licenses/>.
27 #define _trace() do { \
28 struct timeval _ctv; \
29 gettimeofday(&_ctv, NULL); \
34 NSLog(@"%lu.%.6u[%f]:WB:_trace()@%s:%u[%s]\n", \
35 _ctv.tv_sec, _ctv.tv_usec, \
36 (_ctv.tv_sec - _ltv.tv_sec) + (_ctv.tv_usec - _ltv.tv_usec) / 1000000.0, \
37 __FILE__, __LINE__, __FUNCTION__\
44 #import <CoreFoundation/CoreFoundation.h>
45 #import <Foundation/Foundation.h>
46 #import <CoreGraphics/CoreGraphics.h>
47 #import <ImageIO/CGImageSource.h>
49 #import <Celestial/AVController.h>
50 #import <Celestial/AVItem.h>
51 #import <Celestial/AVQueue.h>
53 #include <substrate.h>
55 #import <UIKit/UIKit.h>
57 #import <SpringBoard/SBApplication.h>
58 #import <SpringBoard/SBApplicationIcon.h>
59 #import <SpringBoard/SBAppWindow.h>
60 #import <SpringBoard/SBAwayView.h>
61 #import <SpringBoard/SBBookmarkIcon.h>
62 #import <SpringBoard/SBButtonBar.h>
63 #import <SpringBoard/SBCalendarIconContentsView.h>
64 #import <SpringBoard/SBIconController.h>
65 #import <SpringBoard/SBIconLabel.h>
66 #import <SpringBoard/SBIconList.h>
67 #import <SpringBoard/SBIconModel.h>
68 #import <SpringBoard/SBImageCache.h>
69 // XXX: #import <SpringBoard/SBSearchView.h>
70 #import <SpringBoard/SBSearchTableViewCell.h>
71 #import <SpringBoard/SBStatusBarContentsView.h>
72 #import <SpringBoard/SBStatusBarController.h>
73 #import <SpringBoard/SBStatusBarOperatorNameView.h>
74 #import <SpringBoard/SBStatusBarTimeView.h>
75 #import <SpringBoard/SBUIController.h>
76 #import <SpringBoard/SBWidgetApplicationIcon.h>
78 #import <MobileSMS/mSMSMessageTranscriptController.h>
80 #import <MediaPlayer/MPMoviePlayerController.h>
81 #import <MediaPlayer/MPVideoView.h>
82 #import <MediaPlayer/MPVideoView-PlaybackControl.h>
84 #import <CoreGraphics/CGGeometry.h>
86 #import <ChatKit/CKMessageCell.h>
88 #include <sys/sysctl.h>
92 static void (*$objc_setAssociatedObject)(id object, void *key, id value, objc_AssociationPolicy policy);
93 static id (*$objc_getAssociatedObject)(id object, void *key);
94 static void (*$objc_removeAssociatedObjects)(id object);
100 Class $MPMoviePlayerController;
103 MSClassHook(NSBundle)
104 MSClassHook(NSString)
107 MSMetaClassHook(UIImage)
108 MSClassHook(UINavigationBar)
109 MSClassHook(UISharedArtwork)
110 MSClassHook(UIToolbar)
111 MSClassHook(UIStatusBarTimeItemView)
112 MSClassHook(UIWebDocumentView)
114 MSClassHook(CKBalloonView)
115 MSClassHook(CKMessageCell)
116 MSClassHook(CKTimestampView)
117 MSClassHook(CKTranscriptCell)
118 MSClassHook(CKTranscriptController)
119 MSClassHook(CKTranscriptHeaderView)
120 MSClassHook(CKTranscriptTableView)
122 MSClassHook(SBApplication)
123 MSClassHook(SBApplicationIcon)
124 MSClassHook(SBAwayView)
125 MSClassHook(SBBookmarkIcon)
126 MSClassHook(SBButtonBar)
127 MSClassHook(SBCalendarApplicationIcon)
128 MSClassHook(SBCalendarIconContentsView)
129 MSClassHook(SBDockIconListView)
131 MSClassHook(SBIconAccessoryImage)
132 MSMetaClassHook(SBIconAccessoryImage)
133 MSClassHook(SBIconBadge)
134 MSClassHook(SBIconBadgeFactory)
135 MSClassHook(SBIconBadgeImage)
136 MSClassHook(SBIconContentView)
137 MSClassHook(SBIconController)
138 MSClassHook(SBIconLabel)
139 MSClassHook(SBIconLabelImage)
140 MSMetaClassHook(SBIconLabelImage)
141 MSClassHook(SBIconLabelImageParameters)
142 MSClassHook(SBIconList)
143 MSClassHook(SBIconModel)
144 MSClassHook(SBIconView)
145 MSMetaClassHook(SBIconView)
146 //MSClassHook(SBImageCache)
147 MSClassHook(SBSearchView)
148 MSClassHook(SBSearchTableViewCell)
149 MSClassHook(SBSlidingAlertDisplay)
150 MSClassHook(SBStatusBarContentsView)
151 MSClassHook(SBStatusBarController)
152 MSClassHook(SBStatusBarOperatorNameView)
153 MSClassHook(SBStatusBarTimeView)
154 MSClassHook(SBUIController)
155 MSClassHook(SBWallpaperView)
156 MSClassHook(SBWidgetApplicationIcon)
158 extern "C" void WKSetCurrentGraphicsContext(CGContextRef);
160 static struct MSFixClass { MSFixClass() {
161 $UIWebDocumentView = objc_getClass("UIWebBrowserView") ?: $UIWebDocumentView;
162 $SBIcon = objc_getClass("SBIconView") ?: $SBIcon;
164 if ($SBIconList == nil)
165 $SBIconList = objc_getClass("SBIconListView");
166 if ($CKTranscriptController == nil)
167 $CKTranscriptController = objc_getClass("mSMSMessageTranscriptController");
171 static bool Four_($SBDockIconListView != nil);
173 @interface NSObject (wb$SBIconAccessoryImage)
174 + (Class) _imageClassForIcon:(SBIcon *)icon location:(int)location;
177 @interface NSDictionary (WinterBoard)
178 - (UIColor *) wb$colorForKey:(NSString *)key;
179 - (BOOL) wb$boolForKey:(NSString *)key;
182 @implementation NSDictionary (WinterBoard)
184 - (UIColor *) wb$colorForKey:(NSString *)key {
185 NSString *value = [self objectForKey:key];
192 - (BOOL) wb$boolForKey:(NSString *)key {
193 if (NSString *value = [self objectForKey:key])
194 return [value boolValue];
200 static BOOL (*_GSFontGetUseLegacyFontMetrics)();
201 #define $GSFontGetUseLegacyFontMetrics() \
202 (_GSFontGetUseLegacyFontMetrics == NULL ? YES : _GSFontGetUseLegacyFontMetrics())
204 static bool Debug_ = false;
205 static bool UIDebug_ = false;
206 static bool Engineer_ = false;
207 static bool SummerBoard_ = false;
208 static bool SpringBoard_;
210 static UIImage *(*_UIApplicationImageWithName)(NSString *name);
211 static UIImage *(*_UIImageWithNameInDomain)(NSString *name, NSString *domain);
212 static UIImage *(*_UIImageWithNameUsingCurrentIdiom)(NSString *name);
213 static UIImage *(*_UIImageWithDeviceSpecificName)(NSString *name);
214 static NSBundle *(*_UIKitBundle)();
215 static bool (*_UIPackedImageTableGetIdentifierForName)(NSString *, int *);
216 static int (*_UISharedImageNameGetIdentifier)(NSString *);
218 static NSMutableDictionary *Images_ = [[NSMutableDictionary alloc] initWithCapacity:64];
219 static NSMutableDictionary *Cache_ = [[NSMutableDictionary alloc] initWithCapacity:64];
220 static NSMutableDictionary *Strings_ = [[NSMutableDictionary alloc] initWithCapacity:0];
221 static NSMutableDictionary *Bundles_ = [[NSMutableDictionary alloc] initWithCapacity:2];
223 static NSFileManager *Manager_;
224 static NSMutableArray *Themes_;
226 static NSDictionary *English_;
227 static NSMutableDictionary *Info_;
230 static NSMutableDictionary *Themed_ = [[NSMutableDictionary alloc] initWithCapacity:128];
232 static unsigned Scale_ = 0;
234 static unsigned $getScale$(NSString *path) {
235 NSString *name(path);
237 #define StripName(strip) \
238 if ([name hasSuffix:@ strip]) \
239 name = [name substringWithRange:NSMakeRange(0, [name length] - sizeof(strip) - 1)];
243 StripName("~iphone");
246 return [name hasSuffix:@"@2x"] ? 2 : 1;
249 static NSArray *$useScale$(NSArray *files, bool use = true) {
250 if (use && Scale_ == 0) {
251 UIScreen *screen([UIScreen mainScreen]);
252 if ([screen respondsToSelector:@selector(scale)])
253 Scale_ = [screen scale];
261 NSString *idiom(IsWild_ ? @"ipad" : @"iphone");
263 NSMutableArray *scaled([NSMutableArray arrayWithCapacity:([files count] * 4)]);
265 for (NSString *file in files) {
266 NSString *base([file stringByDeletingPathExtension]);
267 NSString *extension([file pathExtension]);
271 [scaled addObject:[NSString stringWithFormat:@"%@@2x~%@.%@", base, idiom, extension]];
272 [scaled addObject:[NSString stringWithFormat:@"%@@2x.%@", base, extension]];
275 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
277 // if (!IsWild_) <- support old themes
278 [scaled addObject:file];
279 } else if ([base hasSuffix: @"@2x"]) {
280 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
281 [scaled addObject:file];
283 // XXX: this actually can't be used, as the person loading the file doesn't realize that the @2x changed
284 /*NSString *rest([base substringWithRange:NSMakeRange(0, [base length] - 3)]);
285 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", rest, idiom, extension]];
286 [scaled addObject:[rest stringByAppendingPathExtension:extension]];*/
288 // XXX: this code isn't really complete
290 [scaled addObject:file];
292 if ([base hasSuffix:[NSString stringWithFormat:@"~%@", idiom]])
293 [scaled addObject:[[base substringWithRange:NSMakeRange(0, [base length] - 1 - [idiom length])] stringByAppendingPathExtension:extension]];
300 static NSString *$getTheme$(NSArray *files, NSArray *themes = Themes_) {
301 // XXX: this is not reasonable; OMG
304 @synchronized (Themed_) {
305 if (NSString *path = [Themed_ objectForKey:key])
306 return reinterpret_cast<id>(path) == [NSNull null] ? nil : path;
310 NSLog(@"WB:Debug: %@", [files description]);
314 for (NSString *theme in Themes_)
315 for (NSString *file in files) {
316 path = [NSString stringWithFormat:@"%@/%@", theme, file];
317 if ([Manager_ fileExistsAtPath:path]) {
318 if ([[Manager_ destinationOfSymbolicLinkAtPath:path error:NULL] isEqualToString:@"/"])
327 @synchronized (Themed_) {
328 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:key];
334 // $pathForFile$inBundle$() {{{
335 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool ui, bool use) {
336 NSString *identifier = [bundle bundleIdentifier];
337 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
339 if (identifier != nil)
340 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
341 if (NSString *folder = [[bundle bundlePath] lastPathComponent]) {
342 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
343 NSString *base([folder stringByDeletingPathExtension]);
344 if ([base hasSuffix:@"~iphone"])
345 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 7)], [folder pathExtension], file]];
346 if ([base hasSuffix:@"~ipad"])
347 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 5)], [folder pathExtension], file]];
350 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
352 #define remapResourceName(oldname, newname) \
353 else if ([file isEqualToString:(oldname)]) \
354 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
356 bool summer(SpringBoard_ && SummerBoard_);
358 if (identifier == nil);
359 else if ([identifier isEqualToString:@"com.apple.chatkit"])
360 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
361 else if ([identifier isEqualToString:@"com.apple.calculator"])
362 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
363 else if ([identifier isEqualToString:@"com.apple.Maps"] && [file isEqualToString:@"Icon-57@2x.png"])
364 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.Maps/icon.png"]];
366 remapResourceName(@"FSO_BG.png", @"StatusBar")
367 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
368 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
370 [names addObject:[NSString stringWithFormat:@"Fallback/%@", file]];
372 if (NSString *path = $getTheme$($useScale$(names, use)))
379 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
380 NSString *identifier = [self bundleIdentifier];
381 NSString *path = [self path];
382 NSString *folder = [path lastPathComponent];
383 NSString *dname = [self displayName];
384 NSString *didentifier = [self displayIdentifier];
387 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
389 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
391 /* XXX: I might need to keep this for backwards compatibility
392 if (identifier != nil)
393 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
395 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
397 #define testForIcon(Name) \
398 if (NSString *name = Name) \
399 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
401 if (![didentifier isEqualToString:identifier])
402 testForIcon(didentifier);
404 testForIcon(identifier);
407 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
410 if (didentifier != nil) {
411 testForIcon([English_ objectForKey:didentifier]);
413 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
414 if ([parts count] != 1)
415 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
416 testForIcon([english objectForKey:[parts lastObject]]);
419 if (NSString *path = $getTheme$(names))
425 // -[NSBundle wb$bundleWithFile] {{{
426 @interface NSBundle (WinterBoard)
427 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
430 @implementation NSBundle (WinterBoard)
432 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
433 path = [path stringByDeletingLastPathComponent];
434 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
437 NSBundle *bundle([Bundles_ objectForKey:path]);
438 if (reinterpret_cast<id>(bundle) == [NSNull null])
440 else if (bundle == nil) {
441 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
442 bundle = [NSBundle bundleWithPath:path];
444 bundle = [NSBundle wb$bundleWithFile:path];
446 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
447 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
455 // -[NSString wb$themedPath] {{{
456 @interface NSString (WinterBoard)
457 - (NSString *) wb$themedPath;
460 @implementation NSString (WinterBoard)
462 - (NSString *) wb$themedPath {
463 if ([self hasPrefix:@"/Library/Themes/"])
467 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
469 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
470 NSString *file([self stringByResolvingSymlinksInPath]);
471 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
472 if ([file hasPrefix:prefix]) {
473 NSUInteger length([prefix length]);
474 if (length != [file length])
475 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false, false))
486 void WBLogRect(const char *tag, struct CGRect rect) {
487 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
490 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
491 CGRect frame([view frame]);
492 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]);
494 for (UIView *child in [view subviews])
495 WBLogHierarchy(child, index++, indent + 1);
498 UIImage *$cacheForImage$(UIImage *image) {
499 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
500 CGRect rect = {CGPointMake(1, 1), [image size]};
501 CGSize size = {rect.size.width + 2, rect.size.height + 2};
503 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
504 CGColorSpaceRelease(space);
506 CGContextDrawImage(context, rect, [image CGImage]);
507 CGImageRef ref(CGBitmapContextCreateImage(context));
508 CGContextRelease(context);
510 UIImage *cache([UIImage imageWithCGImage:ref]);
516 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
517 //if ([name isEqualToString:@"icons"]) return nil;
518 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
521 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
522 NSString *key([icon displayIdentifier]);
524 if (UIImage *image = [icon icon]) {
525 CGSize size = [image size];
526 if (size.width != 59 || size.height != 60) {
527 UIImage *cache($cacheForImage$(image));
528 [Cache_ setObject:cache forKey:key];
533 _SBIconModel$cacheImageForIcon$(self, sel, icon);
536 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
537 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
538 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
540 NSString *key([icon displayIdentifier]);
542 if (UIImage *image = [icon icon]) {
543 CGSize size = [image size];
544 if (size.width != 59 || size.height != 60) {
545 UIImage *cache($cacheForImage$(image));
546 [Cache_ setObject:cache forKey:key];
552 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
553 NSString *key([icon displayIdentifier]);
554 if (UIImage *image = [Cache_ objectForKey:key])
557 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
560 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
562 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
563 NSString *key([icon displayIdentifier]);
564 if (UIImage *image = [Cache_ objectForKey:key])
567 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
570 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
571 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
572 [self setBackgroundColor:[UIColor clearColor]];
573 for (UIView *child in [self subviews])
574 [child setBackgroundColor:[UIColor clearColor]];
578 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
579 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
580 [self setBackgroundColor:[UIColor clearColor]];
584 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
585 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
586 float inset([self edgeInset]);
587 [[UIColor clearColor] set];
588 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
589 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
592 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
593 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
594 if (NSString *path = $pathForIcon$([self application]))
595 return [UIImage imageWithContentsOfFile:path];
596 return _SBApplicationIcon$icon(self, sel);
599 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
601 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
602 if (IsWild_ && false) // XXX: delete this code, it should not be supported
603 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
604 return [UIImage imageWithContentsOfFile:path72];
605 if (NSString *path = $pathForIcon$([self application]))
606 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
608 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
609 width = [$SBIcon defaultIconImageSize].width;
612 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
615 return _SBApplicationIcon$generateIconImage$(self, sel, type);
618 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
620 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
621 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
622 return [UIImage imageWithContentsOfFile:path];
623 return _SBWidgetApplicationIcon$icon(self, sel);
626 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
628 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
629 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
630 return [UIImage imageWithContentsOfFile:path];
631 return _SBBookmarkIcon$icon(self, sel);
634 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
635 if (NSString *path = $pathForIcon$(self))
637 return _SBApplication$pathForIcon(self, sel);
640 static UIImage *CachedImageAtPath(NSString *path) {
641 path = [path stringByResolvingSymlinksInPath];
642 UIImage *image = [Images_ objectForKey:path];
644 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
645 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
647 image = [image autorelease];
648 [Images_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
652 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
653 NSBundle *bundle = [NSBundle mainBundle];
655 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
656 if (NSString *path = $pathForFile$inBundle$(name, bundle, false, false))
657 return CachedImageAtPath(path);
658 return __UIApplicationImageWithName(name);
661 #define WBDelegate(delegate) \
662 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
664 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
665 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
667 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
671 - (void) forwardInvocation:(NSInvocation*)inv { \
672 SEL sel = [inv selector]; \
673 if ([delegate respondsToSelector:sel]) \
674 [inv invokeWithTarget:delegate]; \
676 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
679 // %hook -[NSBundle pathForResource:ofType:] {{{
680 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
681 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
683 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
684 if (NSString *path = $pathForFile$inBundle$(file, self, false, false))
686 return MSOldCall(resource, type);
690 static void $drawLabel$(NSString *label, CGRect rect, NSString *style, NSString *custom) {
691 bool ellipsis(false);
692 float max = rect.size.width - 11, width;
694 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
697 size_t length([label length]);
698 float spacing((width - max) / (length - 1));
700 if (spacing > 1.25) {
702 label = [label substringToIndex:(length - 1)];
706 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
710 label = [label stringByAppendingString:@"..."];
713 style = [style stringByAppendingString:custom];
715 CGSize size = [label sizeWithStyle:style forWidth:rect.size.width];
716 [label drawAtPoint:CGPointMake((rect.size.width - size.width) / 2 + rect.origin.x, rect.origin.y) withStyle:style];
719 static struct WBStringDrawingState {
720 WBStringDrawingState *next_;
724 } *stringDrawingState_;
726 extern "C" CGColorSpaceRef CGContextGetFillColorSpace(CGContextRef);
727 extern "C" void CGContextGetFillColor(CGContextRef, CGFloat[]);
729 static NSString *WBColorMarkup() {
730 CGContextRef context(UIGraphicsGetCurrentContext());
731 //NSLog(@"XXX:1:%p", context);
735 CGColorSpaceRef space(CGContextGetFillColorSpace(context));
736 //NSLog(@"XXX:2:%p", space);
740 size_t number(CGColorSpaceGetNumberOfComponents(space));
741 //NSLog(@"XXX:3:%u", number);
745 CGFloat components[number + 1];
746 CGContextGetFillColor(context, components);
769 return [NSString stringWithFormat:@"color: rgba(%g, %g, %g, %g)", r * 255, g * 255, b * 255, a];
772 MSInstanceMessageHook6(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode,letterSpacing,includeEmoji, CGPoint, point, float, width, UIFont *, font, UILineBreakMode, mode, float, spacing, BOOL, emoji) {
773 //NSLog(@"XXX: @\"%@\" %g", self, spacing);
775 WBStringDrawingState *state(stringDrawingState_);
777 return MSOldCall(point, width, font, mode, spacing, emoji);
779 if (state->count_ != 0 && --state->count_ == 0)
780 stringDrawingState_ = state->next_;
781 if (state->info_ == nil)
782 return MSOldCall(point, width, font, mode, spacing, emoji);
784 NSString *info([Info_ objectForKey:state->info_]);
786 return MSOldCall(point, width, font, mode, spacing, emoji);
788 NSString *base(state->base_ ?: @"");
789 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
790 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
794 extern "C" NSString *NSStringFromCGRect(CGRect rect);
796 MSInstanceMessageHook7(CGSize, NSString, _drawInRect,withFont,lineBreakMode,alignment,lineSpacing,includeEmoji,truncationRect, CGRect, rect, UIFont *, font, UILineBreakMode, mode, UITextAlignment, alignment, float, spacing, BOOL, emoji, CGRect, truncation) {
797 //NSLog(@"XXX: &\"%@\" %@ \"%@\" %u %u %g %u %@", self, NSStringFromCGRect(rect), font, mode, alignment, spacing, emoji, NSStringFromCGRect(truncation));
799 WBStringDrawingState *state(stringDrawingState_);
801 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
803 if (state->count_ != 0 && --state->count_ == 0)
804 stringDrawingState_ = state->next_;
805 if (state->info_ == nil)
806 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
808 NSString *info([Info_ objectForKey:state->info_]);
810 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
815 case UITextAlignmentLeft:
818 case UITextAlignmentCenter:
819 textAlign = @"center";
821 case UITextAlignmentRight:
822 textAlign = @"right";
826 NSString *base(state->base_ ?: @"");
827 NSString *extra([NSString stringWithFormat:@"text-align: %@", textAlign]);
830 $drawLabel$(self, rect, [NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], WBColorMarkup(), base], info);
832 [self drawInRect:rect withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
837 MSInstanceMessageHook4(CGSize, NSString, sizeWithFont,forWidth,lineBreakMode,letterSpacing, UIFont *, font, float, width, UILineBreakMode, mode, float, spacing) {
838 //NSLog(@"XXX: #\"%@\" \"%@\" %g %u %g", self, font, width, mode, spacing);
840 WBStringDrawingState *state(stringDrawingState_);
842 return MSOldCall(font, width, mode, spacing);
844 if (state->count_ != 0 && --state->count_ == 0)
845 stringDrawingState_ = state->next_;
846 if (state->info_ == nil)
847 return MSOldCall(font, width, mode, spacing);
849 NSString *info([Info_ objectForKey:state->info_]);
851 return MSOldCall(font, width, mode, spacing);
853 NSString *base(state->base_ ?: @"");
854 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
855 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info] forWidth:width];
858 MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) {
859 //NSLog(@"XXX: ?\"%@\"", self);
861 WBStringDrawingState *state(stringDrawingState_);
863 return MSOldCall(font);
865 if (state->count_ != 0 && --state->count_ == 0)
866 stringDrawingState_ = state->next_;
867 if (state->info_ == nil)
868 return MSOldCall(font);
870 NSString *info([Info_ objectForKey:state->info_]);
872 return MSOldCall(font);
874 NSString *base(state->base_ ?: @"");
875 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), base, info] forWidth:65535];
878 MSClassMessageHook2(UIImage *, SBIconAccessoryImage, checkoutAccessoryImageForIcon,location, id, icon, int, location) {
879 if ([self _imageClassForIcon:icon location:location] != $SBIconBadgeImage)
880 return MSOldCall(icon, location);
882 WBStringDrawingState badgeState = {NULL, 0, @""
885 stringDrawingState_ = &badgeState;
887 UIImage *image(MSOldCall(icon, location));
889 stringDrawingState_ = NULL;
893 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
894 WBStringDrawingState badgeState = {NULL, 0, @""
897 stringDrawingState_ = &badgeState;
899 UIImage *image(MSOldCall(text));
901 stringDrawingState_ = NULL;
905 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
906 WBStringDrawingState dayState = {NULL, 2, @""
907 // XXX: this is only correct on an iPod dock
908 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
909 , @"CalendarIconDayStyle"};
911 WBStringDrawingState sizeState = {&dayState, 7, nil, nil};
913 WBStringDrawingState dateState = {&sizeState, 2, @""
914 , @"CalendarIconDateStyle"};
916 stringDrawingState_ = &dateState;
918 UIImage *image(MSOldCall(type));
920 stringDrawingState_ = NULL;
924 MSInstanceMessageHook1(UIImage *, UIStatusBarTimeItemView, contentsImageForStyle, int, style) {
925 WBStringDrawingState timeState = {NULL, 0, @""
928 stringDrawingState_ = &timeState;
930 UIImage *image(MSOldCall(style));
932 stringDrawingState_ = NULL;
936 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
937 NSBundle *bundle([NSBundle mainBundle]);
939 CFLocaleRef locale(CFLocaleCopyCurrent());
940 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
943 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
945 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
946 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
947 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
948 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
952 CFRelease(formatter);
954 NSString *datestyle([@""
955 "font-family: Helvetica; "
956 "font-weight: bold; "
959 "" stringByAppendingString:(IsWild_
960 ? @"font-size: 54px; "
961 : @"font-size: 39px; "
964 NSString *daystyle([@""
965 "font-family: Helvetica; "
966 "font-weight: bold; "
968 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
969 "" stringByAppendingString:(IsWild_
970 ? @"font-size: 11px; "
971 : @"font-size: 9px; "
974 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
975 datestyle = [datestyle stringByAppendingString:style];
976 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
977 daystyle = [daystyle stringByAppendingString:style];
979 float width([self bounds].size.width);
981 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
982 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
984 unsigned base0(IsWild_ ? 89 : 70);
985 if ($GSFontGetUseLegacyFontMetrics())
987 unsigned base1(IsWild_ ? 18 : 16);
994 [(NSString *)date drawAtPoint:CGPointMake(
995 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
996 ) withStyle:datestyle];
998 [(NSString *)day drawAtPoint:CGPointMake(
999 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
1000 ) withStyle:daystyle];
1006 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
1007 void $setBarStyle$_(NSString *name, int &style) {
1009 NSLog(@"WB:Debug:%@Style:%d", name, style);
1010 NSNumber *number = nil;
1012 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
1014 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
1015 if (number != nil) {
1016 style = [number intValue];
1018 NSLog(@"WB:Debug:%@Style=%d", name, style);
1022 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
1023 $setBarStyle$_(@"Toolbar", style);
1024 return MSOldCall(style);
1027 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
1028 $setBarStyle$_(@"NavigationBar", style);
1029 return MSOldCall(style);
1033 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
1034 [[self superview] setBackgroundColor:[UIColor clearColor]];
1035 _SBButtonBar$didMoveToSuperview(self, sel);
1038 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
1039 [[self superview] setBackgroundColor:[UIColor clearColor]];
1040 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
1043 static NSArray *Wallpapers_;
1044 static bool Papered_;
1045 static bool Docked_;
1046 static bool SMSBackgrounded_;
1047 static NSString *WallpaperFile_;
1048 static UIImageView *WallpaperImage_;
1049 static UIWebDocumentView *WallpaperPage_;
1050 static NSURL *WallpaperURL_;
1052 #define _release(object) \
1053 do if (object != nil) { \
1058 static UIImage *$getImage$(NSString *path) {
1059 UIImage *image([UIImage imageWithContentsOfFile:path]);
1061 unsigned scale($getScale$(path));
1062 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
1063 [image setScale:scale];
1068 template <typename Original_, typename Modified_>
1069 _finline UIImage *WBCacheImage(const Original_ &original, const Modified_ &modified, NSString *key) {
1070 UIImage *image([Images_ objectForKey:key]);
1072 return reinterpret_cast<id>(image) == [NSNull null] ? original() : image;
1073 if (NSString *path = modified())
1074 image = $getImage$(path);
1075 [Images_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1076 return image == nil ? original() : image;
1079 static UIImage *$getDefaultDesktopImage$() {
1080 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
1081 return $getImage$(path);
1085 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
1086 return $getDefaultDesktopImage$() ?: MSOldCall();
1089 MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
1090 return $getDefaultDesktopImage$() ?: MSOldCall();
1093 MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
1094 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
1095 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
1096 if (UIImage *image = $getDefaultDesktopImage$()) {
1097 [self setImage:image];
1107 // %hook -[SBUIController init] {{{
1108 MSInstanceMessageHook0(id, SBUIController, init) {
1113 NSString *paper($getTheme$(Wallpapers_));
1115 paper = [paper stringByDeletingLastPathComponent];
1119 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
1120 char *machine = new char[size];
1122 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
1123 perror("sysctlbyname(\"hw.machine\", ?)");
1128 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
1132 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
1135 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
1136 if (&_wallpaperView != NULL) {
1137 [_wallpaperView removeFromSuperview];
1138 [_wallpaperView release];
1139 _wallpaperView = nil;
1143 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
1144 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
1147 if (&_contentLayer != NULL)
1148 player = &_contentLayer;
1149 else if (&_contentView != NULL)
1150 player = &_contentView;
1153 UIView *layer(player == NULL ? nil : *player);
1155 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
1156 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
1157 [window setContentView:content];
1159 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
1160 [window setBackgroundColor:[_window backgroundColor]];
1161 [_window setBackgroundColor:[UIColor clearColor]];
1163 [window setLevel:-1000];
1164 [window setHidden:NO];
1166 /*if (player != NULL)
1167 *player = content;*/
1169 [content setBackgroundColor:[layer backgroundColor]];
1170 [layer setBackgroundColor:[UIColor clearColor]];
1173 if (!SummerBoard_ || !IsWild_)
1176 CGRect bounds([content bounds]);
1177 bounds.origin.y = -30;
1178 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
1179 [content addSubview:indirect];
1180 [indirect zoomToScale:2.4];
1183 _release(WallpaperFile_);
1184 _release(WallpaperImage_);
1185 _release(WallpaperPage_);
1186 _release(WallpaperURL_);
1189 NSArray *themes([NSArray arrayWithObject:paper]);
1191 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1195 static AVController *controller_(nil);
1196 if (controller_ == nil) {
1197 AVQueue *queue([AVQueue avQueue]);
1198 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1201 AVQueue *queue([controller_ queue]);
1203 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1204 [controller_ setLayer:[video _layer]];
1206 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1207 [queue appendItem:item error:&error];
1209 [controller_ play:&error];
1210 #elif UseMPMoviePlayerController
1211 NSURL *url([NSURL fileURLWithPath:path]);
1212 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1213 controller.movieControlMode = MPMovieControlModeHidden;
1216 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1217 [video setMovieWithPath:path];
1218 [video setRepeatMode:1];
1219 [video setRepeatGap:-1];
1220 [video playFromBeginning];;
1223 [indirect addSubview:video];
1226 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1227 if (UIImage *image = $getImage$(path)) {
1228 WallpaperFile_ = [path retain];
1229 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1230 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1231 [WallpaperImage_ setAlpha:[number floatValue]];
1232 [indirect addSubview:WallpaperImage_];
1236 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1237 CGRect bounds = [indirect bounds];
1239 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1240 [view setAutoresizes:true];
1242 WallpaperPage_ = [view retain];
1243 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1245 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1247 [view setBackgroundColor:[UIColor clearColor]];
1248 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1249 [view setDrawsBackground:NO];
1250 [[view webView] setDrawsBackground:NO];
1252 [indirect addSubview:view];
1256 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1257 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1258 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1259 if ([Manager_ fileExistsAtPath:html]) {
1260 CGRect bounds = [indirect bounds];
1262 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1263 [view setAutoresizes:true];
1265 NSURL *url = [NSURL fileURLWithPath:html];
1266 [view loadRequest:[NSURLRequest requestWithURL:url]];
1268 [view setBackgroundColor:[UIColor clearColor]];
1269 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1270 [view setDrawsBackground:NO];
1271 [[view webView] setDrawsBackground:NO];
1273 [indirect addSubview:view];
1281 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1282 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1283 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1285 if (path != nil && _backgroundView != nil)
1288 _SBAwayView$updateDesktopImage$(self, sel, image);
1291 CGRect bounds = [self bounds];
1293 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1294 [view setAutoresizes:true];
1296 if (WallpaperPage_ != nil)
1297 [WallpaperPage_ release];
1298 WallpaperPage_ = [view retain];
1300 if (WallpaperURL_ != nil)
1301 [WallpaperURL_ release];
1302 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1304 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1306 [[view webView] setDrawsBackground:false];
1307 [view setBackgroundColor:[UIColor clearColor]];
1309 [self insertSubview:view aboveSubview:_backgroundView];
1311 if ($objc_setAssociatedObject != NULL)
1312 $objc_setAssociatedObject(self, @selector(wb$widgetView), view, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1316 MSHook(void, SBAwayView$_addSubview$positioned$relativeTo$, SBAwayView *self, SEL sel, UIView *view, int positioned, UIView *relative) {
1317 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1318 UIView *&_chargingView(MSHookIvar<UIView *>(self, "_chargingView"));
1319 if (&_chargingView != NULL)
1320 if (positioned == -2 && (relative == _backgroundView && _chargingView == nil || relative == _chargingView))
1321 if ($objc_getAssociatedObject != NULL)
1322 if (UIView *widget = $objc_getAssociatedObject(self, @selector(wb$widgetView)))
1324 return _SBAwayView$_addSubview$positioned$relativeTo$(self, sel, view, positioned, relative);
1327 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1328 extern "C" CGColorRef CGGStateGetFillColor(void *);
1329 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1330 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1332 /* WBTimeLabel {{{ */
1333 @interface WBTimeLabel : NSProxy {
1335 _transient SBStatusBarTimeView *view_;
1338 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1342 @implementation WBTimeLabel
1349 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1350 time_ = [time retain];
1355 - (NSString *) description {
1361 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1362 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1363 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1365 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1366 "font-family: Helvetica; "
1367 "font-weight: bold; "
1370 "%@", _mode ? @"white" : @"black", custom]];
1375 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1380 /* WBBadgeLabel {{{ */
1381 @interface WBBadgeLabel : NSProxy {
1385 - (id) initWithBadge:(NSString *)badge;
1386 - (NSString *) description;
1390 @implementation WBBadgeLabel
1397 - (id) initWithBadge:(NSString *)badge {
1398 badge_ = [badge retain];
1402 - (NSString *) description {
1403 return [badge_ description];
1408 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1409 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1410 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1411 "font-family: Helvetica; "
1412 "font-weight: bold; "
1420 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1427 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1428 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1429 alpha = [number floatValue];
1430 return MSOldCall(alpha);
1433 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1434 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1435 alpha = [number floatValue];
1436 return MSOldCall(alpha);
1439 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1440 if ((self = MSOldCall()) != nil) {
1441 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1442 // XXX: note: this is overridden above, which is silly
1443 float alpha([number floatValue]);
1444 if ([self respondsToSelector:@selector(setIconImageAlpha:)])
1445 [self setIconImageAlpha:alpha];
1446 if ([self respondsToSelector:@selector(setIconLabelAlpha:)])
1447 [self setIconLabelAlpha:alpha];
1448 if ([self respondsToSelector:@selector(setAlpha:)])
1449 [self setAlpha:alpha];
1454 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1455 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1456 alpha = [number floatValue];
1457 return MSOldCall(alpha);
1461 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1462 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1463 id &_badge(MSHookIvar<id>(self, "_badge"));
1465 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1470 void SBStatusBarController$setStatusBarMode(int &mode) {
1472 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1473 if (mode < 100) // 104:hidden 105:glowing
1474 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1475 mode = [number intValue];
1478 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1479 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1480 SBStatusBarController$setStatusBarMode(mode);
1481 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1484 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1485 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1486 SBStatusBarController$setStatusBarMode(mode);
1487 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1490 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) {
1491 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1492 SBStatusBarController$setStatusBarMode(mode);
1493 //NSLog(@"mode=%u", mode);
1494 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1497 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1498 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1499 mode = [number intValue];
1500 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1503 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1504 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1506 NSLog(@"operatorNameStyle= %@", style);
1507 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1508 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1512 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1514 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1515 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1518 // XXX: replace this with [SBStatusBarTimeView tile]
1519 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1520 id &_time(MSHookIvar<id>(self, "_time"));
1521 if (_time != nil && [_time class] != [WBTimeLabel class])
1522 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1523 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1526 @interface UIView (WinterBoard)
1527 - (bool) wb$isWBImageView;
1528 - (void) wb$logHierarchy;
1529 - (void) wb$setBackgroundColor:(UIColor *)color;
1532 @implementation UIView (WinterBoard)
1534 - (bool) wb$isWBImageView {
1538 - (void) wb$logHierarchy {
1539 WBLogHierarchy(self);
1542 - (void) wb$setBackgroundColor:(UIColor *)color {
1543 [self setBackgroundColor:color];
1544 for (UIView *child in [self subviews])
1545 [child wb$setBackgroundColor:color];
1550 @interface WBImageView : UIImageView {
1553 - (bool) wb$isWBImageView;
1554 - (void) wb$updateFrame;
1557 @implementation WBImageView
1559 - (bool) wb$isWBImageView {
1563 - (void) wb$updateFrame {
1564 CGRect frame([self frame]);
1567 for (UIView *view(self); ; ) {
1568 view = [view superview];
1571 frame.origin.y -= [view frame].origin.y;
1574 [self setFrame:frame];
1579 static void SBIconList$updateFrames$(SBIconList *self) {
1580 NSArray *subviews([self subviews]);
1581 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1582 if (view != nil && [view wb$isWBImageView])
1583 [view wb$updateFrame];
1586 MSHook(void, SBIconList$didMoveToSuperview, SBIconList *self, SEL sel) {
1587 SBIconList$updateFrames$(self);
1588 _SBIconList$didMoveToSuperview(self, sel);
1591 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1592 SBIconList$updateFrames$(self);
1593 _SBIconList$setFrame$(self, sel, frame);
1596 static void $addPerPageView$(unsigned i, UIView *list) {
1597 NSString *path($getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]]));
1601 NSArray *subviews([list subviews]);
1603 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1604 if (view == nil || ![view wb$isWBImageView]) {
1605 view = [[[WBImageView alloc] init] autorelease];
1606 [list insertSubview:view atIndex:0];
1609 UIImage *image([UIImage imageWithContentsOfFile:path]);
1611 CGRect frame([view frame]);
1612 frame.size = [image size];
1613 [view setFrame:frame];
1615 [view setImage:image];
1616 [view wb$updateFrame];
1619 static void $addPerPageViews$(NSArray *lists) {
1620 for (unsigned i(0), e([lists count]); i != e; ++i)
1621 $addPerPageView$(i, [lists objectAtIndex:i]);
1624 MSInstanceMessageHook0(void, SBIconController, updateNumberOfRootIconLists) {
1625 NSArray *&_rootIconLists(MSHookIvar<NSArray *>(self, "_rootIconLists"));
1626 $addPerPageViews$(_rootIconLists);
1630 MSInstanceMessageHook0(void, SBIconContentView, layoutSubviews) {
1633 if (SBIconController *controller = [$SBIconController sharedInstance]) {
1634 UIView *&_dockContainerView(MSHookIvar<UIView *>(controller, "_dockContainerView"));
1635 if (&_dockContainerView != NULL)
1636 [[_dockContainerView superview] bringSubviewToFront:_dockContainerView];
1640 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1641 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1642 $addPerPageViews$([_iconModel iconLists]);
1643 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1646 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1647 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1649 [self setClipsToBounds:NO];
1653 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1654 static bool gssc(false);
1656 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1657 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1660 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1661 [Info_ setObject:[NSNumber numberWithBool:(
1663 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1664 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1665 )] forKey:@"UndockedIconLabels"];
1668 id &_label(MSHookIvar<id>(self, "_label"));
1669 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1672 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1673 [_label setInDock:docked];
1675 _SBIconLabel$setInDock$(self, sel, docked);
1676 [self setNeedsDisplay];
1679 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1680 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1683 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1684 _SBDockIconListView$setFrame$(self, sel, frame);
1687 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1688 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1689 NSString *identifier = [self bundleIdentifier];
1690 NSLocale *locale = [NSLocale currentLocale];
1691 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1693 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1694 NSString *file = table == nil ? @"Localizable" : table;
1695 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1696 NSDictionary *strings;
1697 if ((strings = [Strings_ objectForKey:name]) != nil) {
1698 if (static_cast<id>(strings) != [NSNull null]) strings:
1699 if (NSString *value = [strings objectForKey:key])
1701 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1703 ], self, false, false)) {
1704 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1705 [Strings_ setObject:[strings autorelease] forKey:name];
1709 [Strings_ setObject:[NSNull null] forKey:name];
1710 return MSOldCall(key, value, table);
1713 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1714 MSClassHook(WebCoreFrameBridge)
1716 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1719 void **core(reinterpret_cast<void **>([node _node]));
1720 if (core == NULL || core[6] == NULL)
1722 return MSOldCall(node, width);
1726 MSInstanceMessage1(void, SBIconLabel, drawRect, CGRect, rect) {
1727 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1730 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1731 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1733 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1735 NSString *style = [NSString stringWithFormat:@""
1736 "font-family: Helvetica; "
1737 "font-weight: bold; "
1739 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1740 ? @"font-size: 12px; "
1741 : @"font-size: 11px; "
1745 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1747 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1749 NSString *custom([Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")]);
1751 $drawLabel$(label, [self bounds], style, custom);
1754 MSInstanceMessage0(CGImageRef, SBIconLabel, buildLabelImage) {
1755 bool docked((MSHookIvar<unsigned>(self, "_inDock") & 0x2) != 0);
1757 WBStringDrawingState labelState = {NULL, 0, @""
1758 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1760 stringDrawingState_ = &labelState;
1763 CGImageRef image(MSOldCall());
1766 stringDrawingState_ = NULL;
1770 static bool wb$inDock(id parameters) {
1771 return [$objc_getAssociatedObject(parameters, @selector(wb$inDock)) boolValue];
1774 MSInstanceMessage0(NSUInteger, SBIconLabelImageParameters, hash) {
1775 return MSOldCall() + (wb$inDock(self) ? 0xdeadbeef : 0xd15ea5e);
1778 MSClassMessage2(id, SBIconView, _labelImageParametersForIcon,location, id, icon, int, location) {
1779 if (id parameters = MSOldCall(icon, location)) {
1780 $objc_setAssociatedObject(parameters, @selector(wb$inDock), [NSNumber numberWithBool:(location == 1)], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1785 MSClassMessage1(UIImage *, SBIconLabelImage, _drawLabelImageForParameters, id, parameters) {
1786 bool docked(wb$inDock(parameters));
1788 WBStringDrawingState labelState = {NULL, 0, @""
1789 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1791 stringDrawingState_ = &labelState;
1794 UIImage *image(MSOldCall(parameters));
1797 stringDrawingState_ = NULL;
1802 MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1803 if ((self = MSOldCall(frame, delegate)) != nil) {
1804 [self setBackgroundColor:[UIColor clearColor]];
1808 MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1809 return SMSBackgrounded_ ? NO : MSOldCall();
1812 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1813 [self wb$setBackgroundColor:[UIColor clearColor]];
1817 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1819 [balloon setBackgroundColor:[UIColor clearColor]];
1822 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1823 MSOldCall([UIColor clearColor]);
1824 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1828 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1829 if ((self = MSOldCall(style, reuse)) != nil) {
1830 [self setBackgroundColor:[UIColor clearColor]];
1831 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1836 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1837 if ((self = MSOldCall(style, reuse)) != nil) {
1838 [self setBackgroundColor:[UIColor clearColor]];
1839 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1843 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1844 if ((self = MSOldCall(style, reuse)) != nil) {
1845 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1846 [_label setBackgroundColor:[UIColor clearColor]];
1850 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1851 MSOldCall(UITableViewCellSeparatorStyleNone);
1854 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1855 if ((self = MSOldCall(frame, style)) != nil) {
1856 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1860 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1863 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1864 if (UIImage *image = $getImage$(path)) {
1865 SMSBackgrounded_ = true;
1867 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1868 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1870 if (&_transcriptTable != NULL)
1871 table = _transcriptTable;
1872 else if (&_transcriptLayer != NULL)
1873 table = _transcriptLayer;
1877 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1878 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1881 [placard insertSubview:background atIndex:0];
1883 [table setBackgroundColor:[UIColor clearColor]];
1884 [placard insertSubview:background belowSubview:table];
1890 template <typename Original_>
1891 static UIImage *WBCacheUIImage(const Original_ &original, NSString *name, NSString *key) {
1892 if ([name rangeOfString:@"."].location == NSNotFound)
1893 name = [name stringByAppendingString:@".png"];
1894 UIImage *image(WBCacheImage(original, [=](){ return $pathForFile$inBundle$(name, _UIKitBundle(), true, true); }, key));
1895 if (image != nil && UIDebug_) {
1896 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1897 if (![Manager_ fileExistsAtPath:path])
1898 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1902 // %hook _UIImageWithName() {{{
1903 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1907 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1908 return WBCacheUIImage(
1909 [=](){ return __UIImageWithName(name); },
1910 name, [NSString stringWithFormat:@"I:%@", name]);
1913 // %hook _UIImageWithNameInDomain() {{{
1914 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1916 NSLog(@"WB:Debug: _UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1917 return WBCacheImage(
1918 [=](){ return __UIImageWithNameInDomain(name, domain); },
1919 [=](){ return $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])); },
1920 [NSString stringWithFormat:@"D:%zu:%@%@", size_t([domain length]), domain, name]);
1923 // %hook _UIImageWithDeviceUsingCurrentIdiom() {{{
1924 MSHook(UIImage *, _UIImageWithNameUsingCurrentIdiom, NSString *name) {
1926 NSLog(@"WB:Debug: _UIImageWithNameUsingCurrentIdiom(\"%@\")", name);
1927 return WBCacheUIImage(
1928 [=](){ return __UIImageWithNameUsingCurrentIdiom(name); },
1929 name, [NSString stringWithFormat:@"I:%@", name]);
1932 // %hook _UIImageWithDeviceSpecificName() {{{
1933 MSHook(UIImage *, _UIImageWithDeviceSpecificName, NSString *name) {
1935 NSLog(@"WB:Debug: _UIImageWithDeviceSpecificName(\"%@\")", name);
1936 return WBCacheUIImage(
1937 [=](){ return __UIImageWithDeviceSpecificName(name); },
1938 name, [NSString stringWithFormat:@"S:%@", name]);
1942 // %hook GSFontCreateWithName() {{{
1943 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1945 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1946 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1947 name = [font UTF8String];
1948 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1949 // size *= [scale floatValue];
1950 return _GSFontCreateWithName(name, traits, size);
1954 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1956 static bool GetFileNameForThisAction$(bool value, unsigned long a0, char *a1, unsigned long a2, bool &a3) {
1958 NSLog(@"WB:Debug:GetFileNameForThisAction(%lu, %s, %lu, %u) = %u", a0, value ? a1 : NULL, a2, a3, value);
1961 NSString *path = [NSString stringWithUTF8String:a1];
1962 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1963 NSString *file = [path substringFromIndex:31];
1964 for (NSString *theme in Themes_) {
1965 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1966 if ([Manager_ fileExistsAtPath:path]) {
1967 strcpy(a1, [path UTF8String]);
1976 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a3) {
1977 bool value(__Z24GetFileNameForThisActionmPcRb(a0, a1, a3));
1978 return GetFileNameForThisAction$(value, a0, a1, 0, a3);
1981 MSHook(bool, _Z24GetFileNameForThisActionmPcmRb, unsigned long a0, char *a1, unsigned long a2, bool &a3) {
1982 bool value(__Z24GetFileNameForThisActionmPcmRb(a0, a1, a2, a3));
1983 return GetFileNameForThisAction$(value, a0, a1, a2, a3);
1986 static void ChangeWallpaper(
1987 CFNotificationCenterRef center,
1991 CFDictionaryRef info
1994 NSLog(@"WB:Debug:ChangeWallpaper!");
1997 if (WallpaperFile_ != nil) {
1998 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
2000 image = [image autorelease];
2003 if (WallpaperImage_ != nil)
2004 [WallpaperImage_ setImage:image];
2005 if (WallpaperPage_ != nil)
2006 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
2010 MSHook(NSArray *, CPBitmapCreateImagesFromPath, NSString *path, NSDictionary **names, void *arg2, void *arg3) {
2011 NSArray *images(_CPBitmapCreateImagesFromPath(path, names, arg2, arg3));
2012 if (images != NULL && *names != nil && CFGetTypeID((CFTypeRef) *names) == CFDictionaryGetTypeID()) {
2013 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:path]) {
2014 NSMutableArray *copy([images mutableCopy]);
2018 NSString *file([path stringByResolvingSymlinksInPath]);
2019 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
2020 if ([file hasPrefix:prefix]) {
2021 NSUInteger length([prefix length]);
2022 if (length != [file length]) {
2023 NSEnumerator *enumerator([*names keyEnumerator]);
2024 while (NSString *name = [enumerator nextObject]) {
2025 NSString *png([name stringByAppendingString:@".png"]);
2026 if (NSString *themed = $pathForFile$inBundle$(png, bundle, false, true)) {
2027 NSUInteger index([[*names objectForKey:name] intValue]);
2028 UIImage *image($getImage$(themed));
2029 CGImageRef cg([image CGImage]);
2030 [copy replaceObjectAtIndex:index withObject:(id)cg];
2039 MSHook(void, BKSDisplayServicesSetSystemAppExitedImagePath, NSString *path) {
2040 if (NSString *themed = $getTheme$($useScale$([NSArray arrayWithObject:@"SystemAppExited.png"])))
2042 _BKSDisplayServicesSetSystemAppExitedImagePath(path);
2045 #define WBRename(name, sel, imp) \
2046 MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp, &_ ## name ## $ ## imp)
2048 template <typename Type_>
2049 static void msset(Type_ &function, MSImageRef image, const char *name) {
2050 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
2053 #define WBHookSymbol(image, function) \
2054 msset(function, image, "_" #function)
2056 template <typename Type_>
2057 static void dlset(Type_ &function, const char *name) {
2058 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
2061 // %hook CGImageReadCreateWithFile() {{{
2062 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
2064 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
2065 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2066 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
2071 MSHook(void *, CGImageSourceCreateWithFile, NSString *path, NSDictionary *options) {
2073 NSLog(@"WB:Debug: CGImageSourceCreateWithFile(%@, %@)", path, options);
2074 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2075 void *value(_CGImageSourceCreateWithFile([path wb$themedPath], options));
2080 MSHook(void *, CGImageSourceCreateWithURL, NSURL *url, NSDictionary *options) {
2082 NSLog(@"WB:Debug: CGImageSourceCreateWithURL(%@, %@)", url, options);
2083 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2084 if ([url isFileURL])
2085 url = [NSURL fileURLWithPath:[[url path] wb$themedPath]];
2086 void *value(_CGImageSourceCreateWithURL(url, options));
2092 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
2093 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
2094 if (style == nil || [style length] == 0)
2095 style = @"font-family: Helvetica; font-size: 12px";
2096 //NSLog(@"XXX:drawP(%@ | %@)", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
2097 [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
2100 static void NSString$drawInRect$withStyle$(NSString *self, SEL _cmd, CGRect rect, NSString *style) {
2101 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
2102 if (style == nil || [style length] == 0)
2103 style = @"font-family: Helvetica; font-size: 12px";
2104 //NSLog(@"XXX:drawR(%@ | %@)", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
2105 return [[WBMarkup sharedMarkup] drawString:self inRect:rect withStyle:style];
2108 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
2109 if (style == nil || [style length] == 0)
2110 style = @"font-family: Helvetica; font-size: 12px";
2111 CGSize size([[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width]);
2112 //NSLog(@"XXX:size(%@ | %@) = [%g %g]", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "], size.width, size.height);
2116 static void SBInitialize() {
2118 WBRename(SBApplication, pathForIcon, pathForIcon);
2119 WBRename(SBApplicationIcon, icon, icon);
2120 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
2123 WBRename(SBBookmarkIcon, icon, icon);
2124 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
2125 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
2126 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
2127 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
2129 WBRename(SBWidgetApplicationIcon, icon, icon);
2131 WBRename(SBDockIconListView, setFrame:, setFrame$);
2132 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
2134 if (kCFCoreFoundationVersionNumber < 600 || SummerBoard_)
2135 WBRename(SBIconLabel, drawRect:, drawRect$);
2136 else if (kCFCoreFoundationVersionNumber < 700) {
2137 WBRename(SBIconLabel, buildLabelImage, buildLabelImage);
2139 WBRename(SBIconLabelImageParameters, hash, hash);
2140 WBRename($SBIconView, _labelImageParametersForIcon:location:, _labelImageParametersForIcon$location$);
2141 WBRename($SBIconLabelImage, _drawLabelImageForParameters:, _drawLabelImageForParameters$);
2144 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
2145 WBRename(SBIconLabel, setInDock:, setInDock$);
2147 WBRename(SBIconList, didMoveToSuperview, didMoveToSuperview);
2148 WBRename(SBIconList, setFrame:, setFrame$);
2150 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
2151 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
2152 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
2153 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
2155 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
2156 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
2157 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
2159 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
2161 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
2162 if (kCFCoreFoundationVersionNumber >= 700)
2163 WBRename(SBAwayView, _addSubview:positioned:relativeTo:, _addSubview$positioned$relativeTo$);
2165 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
2166 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
2167 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
2168 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
2169 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
2170 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
2171 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
2172 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
2175 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
2178 /*MSHook(int, open, const char *path, int oflag, mode_t mode) {
2179 int fd(_open(path, oflag, mode));
2181 static bool no(false);
2185 if (strstr(path, "/icon") != NULL)
2186 MSHookProcess(-1, "");
2188 if (fd == -1 && errno == EFAULT)
2189 NSLog(@"open(%p, %#x, %#o) = %d\n", path, oflag, mode, fd);
2191 NSLog(@"open(\"%s\", %#x, %#o) = %d\n", path, oflag, mode, fd);
2198 $objc_setAssociatedObject = reinterpret_cast<void (*)(id, void *, id value, objc_AssociationPolicy)>(dlsym(RTLD_DEFAULT, "objc_setAssociatedObject"));
2199 $objc_getAssociatedObject = reinterpret_cast<id (*)(id, void *)>(dlsym(RTLD_DEFAULT, "objc_getAssociatedObject"));
2200 $objc_removeAssociatedObjects = reinterpret_cast<void (*)(id)>(dlsym(RTLD_DEFAULT, "objc_removeAssociatedObjects"));
2202 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2204 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
2205 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
2207 Manager_ = [[NSFileManager defaultManager] retain];
2208 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
2210 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
2212 // Load Settings.plist {{{
2213 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
2214 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
2215 SummerBoard_ = [value boolValue];
2217 SummerBoard_ = true;
2219 if (NSNumber *value = [settings objectForKey:@"Debug"])
2220 Debug_ = [value boolValue];
2221 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
2222 UIDebug_ = [value boolValue];
2224 NSArray *themes([settings objectForKey:@"Themes"]);
2226 if (NSString *theme = [settings objectForKey:@"Theme"])
2227 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
2229 [NSNumber numberWithBool:true], @"Active",
2233 for (NSDictionary *theme in themes) {
2234 NSNumber *active([theme objectForKey:@"Active"]);
2235 if (![active boolValue])
2238 NSString *name([theme objectForKey:@"Name"]);
2242 #define testForTheme(format...) \
2244 NSString *path = [NSString stringWithFormat:format]; \
2245 if ([Manager_ fileExistsAtPath:path]) { \
2246 [Themes_ addObject:path]; \
2251 testForTheme(@"/Library/Themes/%@.theme", name)
2252 testForTheme(@"/Library/Themes/%@", name)
2253 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
2258 // Merge Info.plist {{{
2259 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2261 for (NSString *theme in Themes_)
2262 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
2263 for (NSString *key in [info allKeys])
2264 if ([Info_ objectForKey:key] == nil)
2265 [Info_ setObject:[info objectForKey:key] forKey:key];
2269 if (MSImageRef image = MSGetImageByName("/System/Library/PrivateFrameworks/AppSupport.framework/AppSupport")) {
2270 NSArray *(*CPBitmapCreateImagesFromPath)(NSString *, NSDictionary **, void *, void *);
2271 msset(CPBitmapCreateImagesFromPath, image, "_CPBitmapCreateImagesFromPath");
2272 MSHookFunction(CPBitmapCreateImagesFromPath, MSHake(CPBitmapCreateImagesFromPath));
2276 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
2277 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long, char *, bool &);
2278 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
2279 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
2281 bool (*_Z24GetFileNameForThisActionmPcmRb)(unsigned long, char *, unsigned long, bool &);
2282 msset(_Z24GetFileNameForThisActionmPcmRb, image, "__Z24GetFileNameForThisActionmPcmRb");
2283 MSHookFunction(_Z24GetFileNameForThisActionmPcmRb, &$_Z24GetFileNameForThisActionmPcmRb, &__Z24GetFileNameForThisActionmPcmRb);
2286 // BackBoardServices {{{
2287 if (MSImageRef image = MSGetImageByName("/System/Library/PrivateFrameworks/BackBoardServices.framework/BackBoardServices")) {
2288 void (*BKSDisplayServicesSetSystemAppExitedImagePath)(NSString *path);
2289 msset(BKSDisplayServicesSetSystemAppExitedImagePath, image, "_BKSDisplayServicesSetSystemAppExitedImagePath");
2290 MSHookFunction(BKSDisplayServicesSetSystemAppExitedImagePath, MSHake(BKSDisplayServicesSetSystemAppExitedImagePath));
2293 // GraphicsServices {{{
2295 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
2299 MSImageRef imageio = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO");
2300 if (imageio == NULL)
2301 imageio = MSGetImageByName("/System/Library/PrivateFrameworks/ImageIO.framework/ImageIO");
2302 if (MSImageRef image = imageio) {
2303 void *(*CGImageReadCreateWithFile)(NSString *, int) = NULL;
2304 if (kCFCoreFoundationVersionNumber > 700) // XXX: iOS 6.x
2305 CGImageReadCreateWithFile = NULL;
2307 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
2308 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
2311 if (CGImageReadCreateWithFile == NULL) {
2312 void *(*CGImageSourceCreateWithFile)(NSString *, NSDictionary *);
2313 msset(CGImageSourceCreateWithFile, image, "_CGImageSourceCreateWithFile");
2314 MSHookFunction(CGImageSourceCreateWithFile, MSHake(CGImageSourceCreateWithFile));
2316 void *(*CGImageSourceCreateWithURL)(NSURL *, NSDictionary *);
2317 msset(CGImageSourceCreateWithURL, image, "_CGImageSourceCreateWithURL");
2318 MSHookFunction(CGImageSourceCreateWithURL, MSHake(CGImageSourceCreateWithURL));
2324 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
2325 Papered_ = $getTheme$(Wallpapers_) != nil;
2326 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
2328 CFNotificationCenterAddObserver(
2329 CFNotificationCenterGetDarwinNotifyCenter(),
2330 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, CFNotificationSuspensionBehaviorCoalesce
2333 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
2334 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
2335 if (MediaPlayer != nil)
2338 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
2339 $MPVideoView = objc_getClass("MPVideoView");
2346 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/UIKit.framework/UIKit")) {
2347 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
2348 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v28@0:4{CGRect={CGSize=ff}{CGSize=ff}}8@24");
2349 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
2351 WBHookSymbol(image, _UIKitBundle);
2352 WBHookSymbol(image, _UIPackedImageTableGetIdentifierForName);
2353 WBHookSymbol(image, _UISharedImageNameGetIdentifier);
2355 MSHookFunction(_UIImageWithName, MSHake(_UIImageWithName));
2357 WBHookSymbol(image, _UIApplicationImageWithName);
2358 MSHookFunction(_UIApplicationImageWithName, MSHake(_UIApplicationImageWithName));
2360 WBHookSymbol(image, _UIImageWithNameInDomain);
2361 MSHookFunction(_UIImageWithNameInDomain, MSHake(_UIImageWithNameInDomain));
2363 WBHookSymbol(image, _UIImageWithNameUsingCurrentIdiom);
2364 MSHookFunction(_UIImageWithNameUsingCurrentIdiom, MSHake(_UIImageWithNameUsingCurrentIdiom));
2366 WBHookSymbol(image, _UIImageWithDeviceSpecificName);
2367 MSHookFunction(_UIImageWithDeviceSpecificName, MSHake(_UIImageWithDeviceSpecificName));
2371 //MSHookFunction(reinterpret_cast<int (*)(const char *, int, mode_t)>(&open), MSHake(open));
2373 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
2374 NSError *error(nil);
2375 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
2376 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
2378 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);