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 static void (*$objc_setAssociatedObject)(id object, void *key, id value, objc_AssociationPolicy policy);
111 static id (*$objc_getAssociatedObject)(id object, void *key);
112 static void (*$objc_removeAssociatedObjects)(id object);
114 @protocol WinterBoard
118 Class $MPMoviePlayerController;
121 MSClassHook(NSBundle)
122 MSClassHook(NSString)
125 MSMetaClassHook(UIImage)
126 MSClassHook(UINavigationBar)
127 MSClassHook(UIToolbar)
128 MSClassHook(UIStatusBarTimeItemView)
129 MSClassHook(UIWebDocumentView)
131 MSClassHook(CKBalloonView)
132 MSClassHook(CKMessageCell)
133 MSClassHook(CKTimestampView)
134 MSClassHook(CKTranscriptCell)
135 MSClassHook(CKTranscriptController)
136 MSClassHook(CKTranscriptHeaderView)
137 MSClassHook(CKTranscriptTableView)
139 MSClassHook(SBApplication)
140 MSClassHook(SBApplicationIcon)
141 MSClassHook(SBAwayView)
142 MSClassHook(SBBookmarkIcon)
143 MSClassHook(SBButtonBar)
144 MSClassHook(SBCalendarApplicationIcon)
145 MSClassHook(SBCalendarIconContentsView)
146 MSClassHook(SBDockIconListView)
148 MSClassHook(SBIconAccessoryImage)
149 MSMetaClassHook(SBIconAccessoryImage)
150 MSClassHook(SBIconBadge)
151 MSClassHook(SBIconBadgeFactory)
152 MSClassHook(SBIconBadgeImage)
153 MSClassHook(SBIconContentView)
154 MSClassHook(SBIconController)
155 MSClassHook(SBIconLabel)
156 MSClassHook(SBIconLabelImage)
157 MSMetaClassHook(SBIconLabelImage)
158 MSClassHook(SBIconLabelImageParameters)
159 MSClassHook(SBIconList)
160 MSClassHook(SBIconModel)
161 MSClassHook(SBIconView)
162 MSMetaClassHook(SBIconView)
163 //MSClassHook(SBImageCache)
164 MSClassHook(SBSearchView)
165 MSClassHook(SBSearchTableViewCell)
166 MSClassHook(SBSlidingAlertDisplay)
167 MSClassHook(SBStatusBarContentsView)
168 MSClassHook(SBStatusBarController)
169 MSClassHook(SBStatusBarOperatorNameView)
170 MSClassHook(SBStatusBarTimeView)
171 MSClassHook(SBUIController)
172 MSClassHook(SBWallpaperView)
173 MSClassHook(SBWidgetApplicationIcon)
175 extern "C" void WKSetCurrentGraphicsContext(CGContextRef);
177 static struct MSFixClass { MSFixClass() {
178 $UIWebDocumentView = objc_getClass("UIWebBrowserView") ?: $UIWebDocumentView;
179 $SBIcon = objc_getClass("SBIconView") ?: $SBIcon;
181 if ($SBIconList == nil)
182 $SBIconList = objc_getClass("SBIconListView");
183 if ($CKTranscriptController == nil)
184 $CKTranscriptController = objc_getClass("mSMSMessageTranscriptController");
188 static bool Four_($SBDockIconListView != nil);
190 @interface NSObject (wb$SBIconAccessoryImage)
191 + (Class) _imageClassForIcon:(SBIcon *)icon location:(int)location;
194 @interface NSDictionary (WinterBoard)
195 - (UIColor *) wb$colorForKey:(NSString *)key;
196 - (BOOL) wb$boolForKey:(NSString *)key;
199 @implementation NSDictionary (WinterBoard)
201 - (UIColor *) wb$colorForKey:(NSString *)key {
202 NSString *value = [self objectForKey:key];
209 - (BOOL) wb$boolForKey:(NSString *)key {
210 if (NSString *value = [self objectForKey:key])
211 return [value boolValue];
217 static BOOL (*_GSFontGetUseLegacyFontMetrics)();
218 #define $GSFontGetUseLegacyFontMetrics() \
219 (_GSFontGetUseLegacyFontMetrics == NULL ? YES : _GSFontGetUseLegacyFontMetrics())
221 static bool Debug_ = false;
222 static bool UIDebug_ = false;
223 static bool Engineer_ = false;
224 static bool SummerBoard_ = false;
225 static bool SpringBoard_;
227 static UIImage *(*_UIApplicationImageWithName)(NSString *name);
228 static UIImage *(*_UIImageWithNameInDomain)(NSString *name, NSString *domain);
229 static NSBundle *(*_UIKitBundle)();
230 static bool (*_UIPackedImageTableGetIdentifierForName)(NSString *, int *);
231 static int (*_UISharedImageNameGetIdentifier)(NSString *);
233 static NSMutableDictionary *UIImages_ = [[NSMutableDictionary alloc] initWithCapacity:32];
234 static NSMutableDictionary *PathImages_ = [[NSMutableDictionary alloc] initWithCapacity:16];
235 static NSMutableDictionary *Cache_ = [[NSMutableDictionary alloc] initWithCapacity:64];
236 static NSMutableDictionary *Strings_ = [[NSMutableDictionary alloc] initWithCapacity:0];
237 static NSMutableDictionary *Bundles_ = [[NSMutableDictionary alloc] initWithCapacity:2];
239 static NSFileManager *Manager_;
240 static NSMutableArray *Themes_;
242 static NSDictionary *English_;
243 static NSMutableDictionary *Info_;
246 static NSMutableDictionary *Themed_ = [[NSMutableDictionary alloc] initWithCapacity:128];
248 static unsigned Scale_ = 0;
250 static unsigned $getScale$(NSString *path) {
251 NSString *name(path);
253 #define StripName(strip) \
254 if ([name hasSuffix:@ strip]) \
255 name = [name substringWithRange:NSMakeRange(0, [name length] - sizeof(strip) - 1)];
259 StripName("~iphone");
262 return [name hasSuffix:@"@2x"] ? 2 : 1;
265 static NSArray *$useScale$(NSArray *files, bool use = true) {
266 if (use && Scale_ == 0) {
267 UIScreen *screen([UIScreen mainScreen]);
268 if ([screen respondsToSelector:@selector(scale)])
269 Scale_ = [screen scale];
277 NSString *idiom(IsWild_ ? @"ipad" : @"iphone");
279 NSMutableArray *scaled([NSMutableArray arrayWithCapacity:([files count] * 4)]);
281 for (NSString *file in files) {
282 NSString *base([file stringByDeletingPathExtension]);
283 NSString *extension([file pathExtension]);
287 [scaled addObject:[NSString stringWithFormat:@"%@@2x~%@.%@", base, idiom, extension]];
288 [scaled addObject:[NSString stringWithFormat:@"%@@2x.%@", base, extension]];
291 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
293 // if (!IsWild_) <- support old themes
294 [scaled addObject:file];
295 } else if ([base hasSuffix: @"@2x"]) {
296 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
297 [scaled addObject:file];
299 // XXX: this actually can't be used, as the person loading the file doesn't realize that the @2x changed
300 /*NSString *rest([base substringWithRange:NSMakeRange(0, [base length] - 3)]);
301 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", rest, idiom, extension]];
302 [scaled addObject:[rest stringByAppendingPathExtension:extension]];*/
304 // XXX: this code isn't really complete
306 [scaled addObject:file];
308 if ([base hasSuffix:[NSString stringWithFormat:@"~%@", idiom]])
309 [scaled addObject:[[base substringWithRange:NSMakeRange(0, [base length] - 1 - [idiom length])] stringByAppendingPathExtension:extension]];
316 static NSString *$getTheme$(NSArray *files, NSArray *themes = Themes_) {
317 // XXX: this is not reasonable; OMG
320 @synchronized (Themed_) {
321 if (NSString *path = [Themed_ objectForKey:key])
322 return reinterpret_cast<id>(path) == [NSNull null] ? nil : path;
326 NSLog(@"WB:Debug: %@", [files description]);
330 for (NSString *theme in Themes_)
331 for (NSString *file in files) {
332 path = [NSString stringWithFormat:@"%@/%@", theme, file];
333 if ([Manager_ fileExistsAtPath:path]) {
334 if ([[Manager_ pathContentOfSymbolicLinkAtPath:path] isEqualToString:@"/"])
343 @synchronized (Themed_) {
344 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:key];
350 // $pathForFile$inBundle$() {{{
351 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool ui) {
352 NSString *identifier = [bundle bundleIdentifier];
353 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
355 if (identifier != nil)
356 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
357 if (NSString *folder = [[bundle bundlePath] lastPathComponent]) {
358 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
359 NSString *base([folder stringByDeletingPathExtension]);
360 if ([base hasSuffix:@"~iphone"])
361 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 7)], [folder pathExtension], file]];
362 if ([base hasSuffix:@"~ipad"])
363 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 5)], [folder pathExtension], file]];
366 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
368 #define remapResourceName(oldname, newname) \
369 else if ([file isEqualToString:(oldname)]) \
370 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
372 bool summer(SpringBoard_ && SummerBoard_);
374 if (identifier == nil);
375 else if ([identifier isEqualToString:@"com.apple.chatkit"])
376 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
377 else if ([identifier isEqualToString:@"com.apple.calculator"])
378 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
379 else if ([identifier isEqualToString:@"com.apple.Maps"] && [file isEqualToString:@"Icon-57@2x.png"])
380 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.Maps/icon.png"]];
382 remapResourceName(@"FSO_BG.png", @"StatusBar")
383 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
384 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
386 [names addObject:[NSString stringWithFormat:@"Fallback/%@", file]];
388 if (NSString *path = $getTheme$($useScale$(names, ui)))
395 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
396 NSString *identifier = [self bundleIdentifier];
397 NSString *path = [self path];
398 NSString *folder = [path lastPathComponent];
399 NSString *dname = [self displayName];
400 NSString *didentifier = [self displayIdentifier];
403 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
405 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
407 /* XXX: I might need to keep this for backwards compatibility
408 if (identifier != nil)
409 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
411 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
413 #define testForIcon(Name) \
414 if (NSString *name = Name) \
415 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
417 if (![didentifier isEqualToString:identifier])
418 testForIcon(didentifier);
420 testForIcon(identifier);
423 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
426 if (didentifier != nil) {
427 testForIcon([English_ objectForKey:didentifier]);
429 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
430 if ([parts count] != 1)
431 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
432 testForIcon([english objectForKey:[parts lastObject]]);
435 if (NSString *path = $getTheme$(names))
441 // -[NSBundle wb$bundleWithFile] {{{
442 @interface NSBundle (WinterBoard)
443 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
446 @implementation NSBundle (WinterBoard)
448 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
449 path = [path stringByDeletingLastPathComponent];
450 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
453 NSBundle *bundle([Bundles_ objectForKey:path]);
454 if (reinterpret_cast<id>(bundle) == [NSNull null])
456 else if (bundle == nil) {
457 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
458 bundle = [NSBundle bundleWithPath:path];
460 bundle = [NSBundle wb$bundleWithFile:path];
462 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
463 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
471 // -[NSString wb$themedPath] {{{
472 @interface NSString (WinterBoard)
473 - (NSString *) wb$themedPath;
476 @implementation NSString (WinterBoard)
478 - (NSString *) wb$themedPath {
479 if ([self hasPrefix:@"/Library/Themes/"])
483 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
485 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
486 NSString *file([self stringByResolvingSymlinksInPath]);
487 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
488 if ([file hasPrefix:prefix]) {
489 NSUInteger length([prefix length]);
490 if (length != [file length])
491 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
502 void WBLogRect(const char *tag, struct CGRect rect) {
503 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
506 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
507 CGRect frame([view frame]);
508 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]);
510 for (UIView *child in [view subviews])
511 WBLogHierarchy(child, index++, indent + 1);
514 UIImage *$cacheForImage$(UIImage *image) {
515 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
516 CGRect rect = {CGPointMake(1, 1), [image size]};
517 CGSize size = {rect.size.width + 2, rect.size.height + 2};
519 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
520 CGColorSpaceRelease(space);
522 CGContextDrawImage(context, rect, [image CGImage]);
523 CGImageRef ref(CGBitmapContextCreateImage(context));
524 CGContextRelease(context);
526 UIImage *cache([UIImage imageWithCGImage:ref]);
532 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
533 //if ([name isEqualToString:@"icons"]) return nil;
534 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
537 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
538 NSString *key([icon displayIdentifier]);
540 if (UIImage *image = [icon icon]) {
541 CGSize size = [image size];
542 if (size.width != 59 || size.height != 60) {
543 UIImage *cache($cacheForImage$(image));
544 [Cache_ setObject:cache forKey:key];
549 _SBIconModel$cacheImageForIcon$(self, sel, icon);
552 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
553 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
554 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
556 NSString *key([icon displayIdentifier]);
558 if (UIImage *image = [icon icon]) {
559 CGSize size = [image size];
560 if (size.width != 59 || size.height != 60) {
561 UIImage *cache($cacheForImage$(image));
562 [Cache_ setObject:cache forKey:key];
568 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
569 NSString *key([icon displayIdentifier]);
570 if (UIImage *image = [Cache_ objectForKey:key])
573 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
576 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
578 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
579 NSString *key([icon displayIdentifier]);
580 if (UIImage *image = [Cache_ objectForKey:key])
583 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
586 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
587 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
588 [self setBackgroundColor:[UIColor clearColor]];
589 for (UIView *child in [self subviews])
590 [child setBackgroundColor:[UIColor clearColor]];
594 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
595 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
596 [self setBackgroundColor:[UIColor clearColor]];
600 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
601 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
602 float inset([self edgeInset]);
603 [[UIColor clearColor] set];
604 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
605 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
608 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
609 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
610 if (NSString *path = $pathForIcon$([self application]))
611 return [UIImage imageWithContentsOfFile:path];
612 return _SBApplicationIcon$icon(self, sel);
615 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
617 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
618 if (IsWild_ && false) // XXX: delete this code, it should not be supported
619 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
620 return [UIImage imageWithContentsOfFile:path72];
621 if (NSString *path = $pathForIcon$([self application]))
622 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
624 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
625 width = [$SBIcon defaultIconImageSize].width;
628 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
631 return _SBApplicationIcon$generateIconImage$(self, sel, type);
634 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
636 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
637 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
638 return [UIImage imageWithContentsOfFile:path];
639 return _SBWidgetApplicationIcon$icon(self, sel);
642 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
644 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
645 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
646 return [UIImage imageWithContentsOfFile:path];
647 return _SBBookmarkIcon$icon(self, sel);
650 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
651 if (NSString *path = $pathForIcon$(self))
653 return _SBApplication$pathForIcon(self, sel);
656 static UIImage *CachedImageAtPath(NSString *path) {
657 path = [path stringByResolvingSymlinksInPath];
658 UIImage *image = [PathImages_ objectForKey:path];
660 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
661 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
663 image = [image autorelease];
664 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
668 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
669 NSBundle *bundle = [NSBundle mainBundle];
671 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
672 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
673 return CachedImageAtPath(path);
674 return __UIApplicationImageWithName(name);
677 #define WBDelegate(delegate) \
678 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
680 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
681 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
683 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
687 - (void) forwardInvocation:(NSInvocation*)inv { \
688 SEL sel = [inv selector]; \
689 if ([delegate respondsToSelector:sel]) \
690 [inv invokeWithTarget:delegate]; \
692 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
695 // %hook -[NSBundle pathForResource:ofType:] {{{
696 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
697 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
699 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
700 if (NSString *path = $pathForFile$inBundle$(file, self, false))
702 return MSOldCall(resource, type);
706 static void $drawLabel$(NSString *label, CGRect rect, NSString *style, NSString *custom) {
707 bool ellipsis(false);
708 float max = rect.size.width - 11, width;
710 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
713 size_t length([label length]);
714 float spacing((width - max) / (length - 1));
716 if (spacing > 1.25) {
718 label = [label substringToIndex:(length - 1)];
722 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
726 label = [label stringByAppendingString:@"..."];
729 style = [style stringByAppendingString:custom];
731 CGSize size = [label sizeWithStyle:style forWidth:rect.size.width];
732 [label drawAtPoint:CGPointMake((rect.size.width - size.width) / 2 + rect.origin.x, rect.origin.y) withStyle:style];
735 static struct WBStringDrawingState {
736 WBStringDrawingState *next_;
740 } *stringDrawingState_;
742 extern "C" CGColorSpaceRef CGContextGetFillColorSpace(CGContextRef);
743 extern "C" void CGContextGetFillColor(CGContextRef, CGFloat[]);
745 static NSString *WBColorMarkup() {
746 CGContextRef context(UIGraphicsGetCurrentContext());
747 //NSLog(@"XXX:1:%p", context);
751 CGColorSpaceRef space(CGContextGetFillColorSpace(context));
752 //NSLog(@"XXX:2:%p", space);
756 size_t number(CGColorSpaceGetNumberOfComponents(space));
757 //NSLog(@"XXX:3:%u", number);
761 CGFloat components[number + 1];
762 CGContextGetFillColor(context, components);
785 return [NSString stringWithFormat:@"color: rgba(%g, %g, %g, %g)", r * 255, g * 255, b * 255, a];
788 MSInstanceMessageHook6(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode,letterSpacing,includeEmoji, CGPoint, point, float, width, UIFont *, font, UILineBreakMode, mode, float, spacing, BOOL, emoji) {
789 //NSLog(@"XXX: @\"%@\" %g", self, spacing);
791 WBStringDrawingState *state(stringDrawingState_);
793 return MSOldCall(point, width, font, mode, spacing, emoji);
795 if (--state->count_ == 0)
796 stringDrawingState_ = state->next_;
797 if (state->info_ == nil)
798 return MSOldCall(point, width, font, mode, spacing, emoji);
800 NSString *info([Info_ objectForKey:state->info_]);
802 return MSOldCall(point, width, font, mode, spacing, emoji);
804 NSString *base(state->base_ ?: @"");
805 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
806 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
810 extern "C" NSString *NSStringFromCGRect(CGRect rect);
812 MSInstanceMessageHook7(CGSize, NSString, _drawInRect,withFont,lineBreakMode,alignment,lineSpacing,includeEmoji,truncationRect, CGRect, rect, UIFont *, font, UILineBreakMode, mode, UITextAlignment, alignment, float, spacing, BOOL, emoji, CGRect, truncation) {
813 //NSLog(@"XXX: &\"%@\" %@ \"%@\" %u %u %g %u %@", self, NSStringFromCGRect(rect), font, mode, alignment, spacing, emoji, NSStringFromCGRect(truncation));
815 WBStringDrawingState *state(stringDrawingState_);
817 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
819 if (--state->count_ == 0)
820 stringDrawingState_ = state->next_;
821 if (state->info_ == nil)
822 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
824 NSString *info([Info_ objectForKey:state->info_]);
826 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
831 case UITextAlignmentLeft:
834 case UITextAlignmentCenter:
835 textAlign = @"center";
837 case UITextAlignmentRight:
838 textAlign = @"right";
842 NSString *base(state->base_ ?: @"");
843 NSString *extra([NSString stringWithFormat:@"text-align: %@", textAlign]);
846 $drawLabel$(self, rect, [NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], WBColorMarkup(), base], info);
848 [self drawInRect:rect withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
853 MSInstanceMessageHook4(CGSize, NSString, sizeWithFont,forWidth,lineBreakMode,letterSpacing, UIFont *, font, float, width, UILineBreakMode, mode, float, spacing) {
854 //NSLog(@"XXX: #\"%@\" \"%@\" %g %u %g", self, font, width, mode, spacing);
856 WBStringDrawingState *state(stringDrawingState_);
858 return MSOldCall(font, width, mode, spacing);
860 if (--state->count_ == 0)
861 stringDrawingState_ = state->next_;
862 if (state->info_ == nil)
863 return MSOldCall(font, width, mode, spacing);
865 NSString *info([Info_ objectForKey:state->info_]);
867 return MSOldCall(font, width, mode, spacing);
869 NSString *base(state->base_ ?: @"");
870 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
871 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info] forWidth:width];
874 MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) {
875 //NSLog(@"XXX: ?\"%@\"", self);
877 WBStringDrawingState *state(stringDrawingState_);
879 return MSOldCall(font);
881 if (--state->count_ == 0)
882 stringDrawingState_ = state->next_;
883 if (state->info_ == nil)
884 return MSOldCall(font);
886 NSString *info([Info_ objectForKey:state->info_]);
888 return MSOldCall(font);
890 NSString *base(state->base_ ?: @"");
891 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), base, info] forWidth:65535];
894 MSClassMessageHook2(UIImage *, SBIconAccessoryImage, checkoutAccessoryImageForIcon,location, id, icon, int, location) {
895 if ([self _imageClassForIcon:icon location:location] != $SBIconBadgeImage)
896 return MSOldCall(icon, location);
898 WBStringDrawingState badgeState = {NULL, -1, @""
901 stringDrawingState_ = &badgeState;
903 UIImage *image(MSOldCall(icon, location));
905 stringDrawingState_ = NULL;
909 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
910 WBStringDrawingState badgeState = {NULL, -1, @""
913 stringDrawingState_ = &badgeState;
915 UIImage *image(MSOldCall(text));
917 stringDrawingState_ = NULL;
921 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
922 WBStringDrawingState dayState = {NULL, 2, @""
923 // XXX: this is only correct on an iPod dock
924 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
925 , @"CalendarIconDayStyle"};
927 WBStringDrawingState sizeState = {&dayState, 7, nil, nil};
929 WBStringDrawingState dateState = {&sizeState, 2, @""
930 , @"CalendarIconDateStyle"};
932 stringDrawingState_ = &dateState;
934 UIImage *image(MSOldCall(type));
936 stringDrawingState_ = NULL;
940 MSInstanceMessageHook1(UIImage *, UIStatusBarTimeItemView, contentsImageForStyle, int, style) {
941 WBStringDrawingState timeState = {NULL, 0, @""
944 stringDrawingState_ = &timeState;
946 UIImage *image(MSOldCall(style));
948 stringDrawingState_ = NULL;
952 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
953 NSBundle *bundle([NSBundle mainBundle]);
955 CFLocaleRef locale(CFLocaleCopyCurrent());
956 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
959 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
961 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
962 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
963 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
964 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
968 CFRelease(formatter);
970 NSString *datestyle([@""
971 "font-family: Helvetica; "
972 "font-weight: bold; "
975 "" stringByAppendingString:(IsWild_
976 ? @"font-size: 54px; "
977 : @"font-size: 39px; "
980 NSString *daystyle([@""
981 "font-family: Helvetica; "
982 "font-weight: bold; "
984 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
985 "" stringByAppendingString:(IsWild_
986 ? @"font-size: 11px; "
987 : @"font-size: 9px; "
990 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
991 datestyle = [datestyle stringByAppendingString:style];
992 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
993 daystyle = [daystyle stringByAppendingString:style];
995 float width([self bounds].size.width);
997 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
998 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
1000 unsigned base0(IsWild_ ? 89 : 70);
1001 if ($GSFontGetUseLegacyFontMetrics())
1003 unsigned base1(IsWild_ ? 18 : 16);
1010 [(NSString *)date drawAtPoint:CGPointMake(
1011 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
1012 ) withStyle:datestyle];
1014 [(NSString *)day drawAtPoint:CGPointMake(
1015 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
1016 ) withStyle:daystyle];
1022 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
1023 void $setBarStyle$_(NSString *name, int &style) {
1025 NSLog(@"WB:Debug:%@Style:%d", name, style);
1026 NSNumber *number = nil;
1028 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
1030 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
1031 if (number != nil) {
1032 style = [number intValue];
1034 NSLog(@"WB:Debug:%@Style=%d", name, style);
1038 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
1039 $setBarStyle$_(@"Toolbar", style);
1040 return MSOldCall(style);
1043 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
1044 $setBarStyle$_(@"NavigationBar", style);
1045 return MSOldCall(style);
1049 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
1050 [[self superview] setBackgroundColor:[UIColor clearColor]];
1051 _SBButtonBar$didMoveToSuperview(self, sel);
1054 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
1055 [[self superview] setBackgroundColor:[UIColor clearColor]];
1056 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
1059 static NSArray *Wallpapers_;
1060 static bool Papered_;
1061 static bool Docked_;
1062 static bool SMSBackgrounded_;
1063 static NSString *WallpaperFile_;
1064 static UIImageView *WallpaperImage_;
1065 static UIWebDocumentView *WallpaperPage_;
1066 static NSURL *WallpaperURL_;
1068 #define _release(object) \
1069 do if (object != nil) { \
1074 static UIImage *$getImage$(NSString *path) {
1075 UIImage *image([UIImage imageWithContentsOfFile:path]);
1077 unsigned scale($getScale$(path));
1078 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
1079 [image setScale:scale];
1084 static UIImage *$getDefaultDesktopImage$() {
1085 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
1086 return $getImage$(path);
1090 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
1091 return $getDefaultDesktopImage$() ?: MSOldCall();
1094 MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
1095 return $getDefaultDesktopImage$() ?: MSOldCall();
1098 MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
1099 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
1100 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
1101 if (UIImage *image = $getDefaultDesktopImage$()) {
1102 [self setImage:image];
1112 // %hook -[SBUIController init] {{{
1113 MSInstanceMessageHook0(id, SBUIController, init) {
1118 NSString *paper($getTheme$(Wallpapers_));
1120 paper = [paper stringByDeletingLastPathComponent];
1124 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
1125 char *machine = new char[size];
1127 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
1128 perror("sysctlbyname(\"hw.machine\", ?)");
1133 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
1137 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
1140 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
1141 if (&_wallpaperView != NULL) {
1142 [_wallpaperView removeFromSuperview];
1143 [_wallpaperView release];
1144 _wallpaperView = nil;
1148 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
1149 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
1152 if (&_contentLayer != NULL)
1153 player = &_contentLayer;
1154 else if (&_contentView != NULL)
1155 player = &_contentView;
1158 UIView *layer(player == NULL ? nil : *player);
1160 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
1161 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
1162 [window setContentView:content];
1164 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
1165 [window setBackgroundColor:[_window backgroundColor]];
1166 [_window setBackgroundColor:[UIColor clearColor]];
1168 [window setLevel:-1000];
1169 [window setHidden:NO];
1171 /*if (player != NULL)
1172 *player = content;*/
1174 [content setBackgroundColor:[layer backgroundColor]];
1175 [layer setBackgroundColor:[UIColor clearColor]];
1178 if (!SummerBoard_ || !IsWild_)
1181 CGRect bounds([content bounds]);
1182 bounds.origin.y = -30;
1183 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
1184 [content addSubview:indirect];
1185 [indirect zoomToScale:2.4];
1188 _release(WallpaperFile_);
1189 _release(WallpaperImage_);
1190 _release(WallpaperPage_);
1191 _release(WallpaperURL_);
1194 NSArray *themes([NSArray arrayWithObject:paper]);
1196 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1200 static AVController *controller_(nil);
1201 if (controller_ == nil) {
1202 AVQueue *queue([AVQueue avQueue]);
1203 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1206 AVQueue *queue([controller_ queue]);
1208 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1209 [controller_ setLayer:[video _layer]];
1211 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1212 [queue appendItem:item error:&error];
1214 [controller_ play:&error];
1215 #elif UseMPMoviePlayerController
1216 NSURL *url([NSURL fileURLWithPath:path]);
1217 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1218 controller.movieControlMode = MPMovieControlModeHidden;
1221 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1222 [video setMovieWithPath:path];
1223 [video setRepeatMode:1];
1224 [video setRepeatGap:-1];
1225 [video playFromBeginning];;
1228 [indirect addSubview:video];
1231 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1232 if (UIImage *image = $getImage$(path)) {
1233 WallpaperFile_ = [path retain];
1234 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1235 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1236 [WallpaperImage_ setAlpha:[number floatValue]];
1237 [indirect addSubview:WallpaperImage_];
1241 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1242 CGRect bounds = [indirect bounds];
1244 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1245 [view setAutoresizes:true];
1247 WallpaperPage_ = [view retain];
1248 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1250 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1252 [view setBackgroundColor:[UIColor clearColor]];
1253 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1254 [view setDrawsBackground:NO];
1255 [[view webView] setDrawsBackground:NO];
1257 [indirect addSubview:view];
1261 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1262 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1263 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1264 if ([Manager_ fileExistsAtPath:html]) {
1265 CGRect bounds = [indirect bounds];
1267 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1268 [view setAutoresizes:true];
1270 NSURL *url = [NSURL fileURLWithPath:html];
1271 [view loadRequest:[NSURLRequest requestWithURL:url]];
1273 [view setBackgroundColor:[UIColor clearColor]];
1274 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1275 [view setDrawsBackground:NO];
1276 [[view webView] setDrawsBackground:NO];
1278 [indirect addSubview:view];
1286 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1287 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1288 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1290 if (path != nil && _backgroundView != nil)
1293 _SBAwayView$updateDesktopImage$(self, sel, image);
1296 CGRect bounds = [self bounds];
1298 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1299 [view setAutoresizes:true];
1301 if (WallpaperPage_ != nil)
1302 [WallpaperPage_ release];
1303 WallpaperPage_ = [view retain];
1305 if (WallpaperURL_ != nil)
1306 [WallpaperURL_ release];
1307 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1309 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1311 [[view webView] setDrawsBackground:false];
1312 [view setBackgroundColor:[UIColor clearColor]];
1314 [self insertSubview:view aboveSubview:_backgroundView];
1318 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1319 extern "C" CGColorRef CGGStateGetFillColor(void *);
1320 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1321 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1323 /* WBTimeLabel {{{ */
1324 @interface WBTimeLabel : NSProxy {
1326 _transient SBStatusBarTimeView *view_;
1329 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1333 @implementation WBTimeLabel
1340 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1341 time_ = [time retain];
1346 - (NSString *) description {
1352 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1353 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1354 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1356 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1357 "font-family: Helvetica; "
1358 "font-weight: bold; "
1361 "%@", _mode ? @"white" : @"black", custom]];
1366 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1371 /* WBBadgeLabel {{{ */
1372 @interface WBBadgeLabel : NSProxy {
1376 - (id) initWithBadge:(NSString *)badge;
1377 - (NSString *) description;
1381 @implementation WBBadgeLabel
1388 - (id) initWithBadge:(NSString *)badge {
1389 badge_ = [badge retain];
1393 - (NSString *) description {
1394 return [badge_ description];
1399 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1400 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1401 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1402 "font-family: Helvetica; "
1403 "font-weight: bold; "
1411 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1418 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1419 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1420 alpha = [number floatValue];
1421 return MSOldCall(alpha);
1424 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1425 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1426 alpha = [number floatValue];
1427 return MSOldCall(alpha);
1430 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1431 if ((self = MSOldCall()) != nil) {
1432 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1433 // XXX: note: this is overridden above, which is silly
1434 float alpha([number floatValue]);
1435 if ([self respondsToSelector:@selector(setIconImageAlpha:)])
1436 [self setIconImageAlpha:alpha];
1437 if ([self respondsToSelector:@selector(setIconLabelAlpha:)])
1438 [self setIconLabelAlpha:alpha];
1439 if ([self respondsToSelector:@selector(setAlpha:)])
1440 [self setAlpha:alpha];
1445 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1446 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1447 alpha = [number floatValue];
1448 return MSOldCall(alpha);
1452 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1453 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1454 id &_badge(MSHookIvar<id>(self, "_badge"));
1456 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1461 void SBStatusBarController$setStatusBarMode(int &mode) {
1463 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1464 if (mode < 100) // 104:hidden 105:glowing
1465 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1466 mode = [number intValue];
1469 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1470 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1471 SBStatusBarController$setStatusBarMode(mode);
1472 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1475 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1476 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1477 SBStatusBarController$setStatusBarMode(mode);
1478 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1481 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) {
1482 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1483 SBStatusBarController$setStatusBarMode(mode);
1484 //NSLog(@"mode=%u", mode);
1485 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1488 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1489 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1490 mode = [number intValue];
1491 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1494 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1495 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1497 NSLog(@"operatorNameStyle= %@", style);
1498 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1499 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1503 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1505 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1506 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1509 // XXX: replace this with [SBStatusBarTimeView tile]
1510 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1511 id &_time(MSHookIvar<id>(self, "_time"));
1512 if (_time != nil && [_time class] != [WBTimeLabel class])
1513 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1514 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1517 @interface UIView (WinterBoard)
1518 - (bool) wb$isWBImageView;
1519 - (void) wb$logHierarchy;
1520 - (void) wb$setBackgroundColor:(UIColor *)color;
1523 @implementation UIView (WinterBoard)
1525 - (bool) wb$isWBImageView {
1529 - (void) wb$logHierarchy {
1530 WBLogHierarchy(self);
1533 - (void) wb$setBackgroundColor:(UIColor *)color {
1534 [self setBackgroundColor:color];
1535 for (UIView *child in [self subviews])
1536 [child wb$setBackgroundColor:color];
1541 @interface WBImageView : UIImageView {
1544 - (bool) wb$isWBImageView;
1545 - (void) wb$updateFrame;
1548 @implementation WBImageView
1550 - (bool) wb$isWBImageView {
1554 - (void) wb$updateFrame {
1555 CGRect frame([self frame]);
1558 for (UIView *view(self); ; ) {
1559 view = [view superview];
1562 frame.origin.y -= [view frame].origin.y;
1565 [self setFrame:frame];
1570 static void SBIconList$updateFrames$(SBIconList *self) {
1571 NSArray *subviews([self subviews]);
1572 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1573 if (view != nil && [view wb$isWBImageView])
1574 [view wb$updateFrame];
1577 MSHook(void, SBIconList$didMoveToSuperview, SBIconList *self, SEL sel) {
1578 SBIconList$updateFrames$(self);
1579 _SBIconList$didMoveToSuperview(self, sel);
1582 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1583 SBIconList$updateFrames$(self);
1584 _SBIconList$setFrame$(self, sel, frame);
1587 static void $addPerPageView$(unsigned i, UIView *list) {
1588 NSString *path($getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]]));
1592 NSArray *subviews([list subviews]);
1594 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1595 if (view == nil || ![view wb$isWBImageView]) {
1596 view = [[[WBImageView alloc] init] autorelease];
1597 [list insertSubview:view atIndex:0];
1600 UIImage *image([UIImage imageWithContentsOfFile:path]);
1602 CGRect frame([view frame]);
1603 frame.size = [image size];
1604 [view setFrame:frame];
1606 [view setImage:image];
1607 [view wb$updateFrame];
1610 static void $addPerPageViews$(NSArray *lists) {
1611 for (unsigned i(0), e([lists count]); i != e; ++i)
1612 $addPerPageView$(i, [lists objectAtIndex:i]);
1615 MSInstanceMessageHook0(void, SBIconController, updateNumberOfRootIconLists) {
1616 NSArray *&_rootIconLists(MSHookIvar<NSArray *>(self, "_rootIconLists"));
1617 $addPerPageViews$(_rootIconLists);
1621 MSInstanceMessageHook0(void, SBIconContentView, layoutSubviews) {
1624 if (SBIconController *controller = [$SBIconController sharedInstance]) {
1625 UIView *&_dockContainerView(MSHookIvar<UIView *>(controller, "_dockContainerView"));
1626 if (&_dockContainerView != NULL)
1627 [[_dockContainerView superview] bringSubviewToFront:_dockContainerView];
1631 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1632 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1633 $addPerPageViews$([_iconModel iconLists]);
1634 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1637 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1638 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1640 [self setClipsToBounds:NO];
1644 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1645 static bool gssc(false);
1647 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1648 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1651 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1652 [Info_ setObject:[NSNumber numberWithBool:(
1654 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1655 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1656 )] forKey:@"UndockedIconLabels"];
1659 id &_label(MSHookIvar<id>(self, "_label"));
1660 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1663 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1664 [_label setInDock:docked];
1666 _SBIconLabel$setInDock$(self, sel, docked);
1667 [self setNeedsDisplay];
1670 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1671 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1674 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1675 _SBDockIconListView$setFrame$(self, sel, frame);
1678 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1679 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1680 NSString *identifier = [self bundleIdentifier];
1681 NSLocale *locale = [NSLocale currentLocale];
1682 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1684 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1685 NSString *file = table == nil ? @"Localizable" : table;
1686 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1687 NSDictionary *strings;
1688 if ((strings = [Strings_ objectForKey:name]) != nil) {
1689 if (static_cast<id>(strings) != [NSNull null]) strings:
1690 if (NSString *value = [strings objectForKey:key])
1692 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1695 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1696 [Strings_ setObject:[strings autorelease] forKey:name];
1700 [Strings_ setObject:[NSNull null] forKey:name];
1701 return MSOldCall(key, value, table);
1704 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1705 MSClassHook(WebCoreFrameBridge)
1707 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1710 void **core(reinterpret_cast<void **>([node _node]));
1711 if (core == NULL || core[6] == NULL)
1713 return MSOldCall(node, width);
1717 MSInstanceMessage1(void, SBIconLabel, drawRect, CGRect, rect) {
1718 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1721 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1722 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1724 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1726 NSString *style = [NSString stringWithFormat:@""
1727 "font-family: Helvetica; "
1728 "font-weight: bold; "
1730 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1731 ? @"font-size: 12px; "
1732 : @"font-size: 11px; "
1736 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1738 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1740 NSString *custom([Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")]);
1742 $drawLabel$(label, [self bounds], style, custom);
1745 MSInstanceMessage0(CGImageRef, SBIconLabel, buildLabelImage) {
1746 bool docked((MSHookIvar<unsigned>(self, "_inDock") & 0x2) != 0);
1748 WBStringDrawingState labelState = {NULL, 0, @""
1749 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1751 stringDrawingState_ = &labelState;
1754 CGImageRef image(MSOldCall());
1757 stringDrawingState_ = NULL;
1761 static bool wb$inDock(id parameters) {
1762 return [$objc_getAssociatedObject(parameters, @selector(wb$inDock)) boolValue];
1765 MSInstanceMessage0(NSUInteger, SBIconLabelImageParameters, hash) {
1766 return MSOldCall() + (wb$inDock(self) ? 0xdeadbeef : 0xd15ea5e);
1769 MSClassMessage2(id, SBIconView, _labelImageParametersForIcon,location, id, icon, int, location) {
1770 if (id parameters = MSOldCall(icon, location)) {
1771 $objc_setAssociatedObject(parameters, @selector(wb$inDock), [NSNumber numberWithBool:(location == 1)], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1776 MSClassMessage1(UIImage *, SBIconLabelImage, _drawLabelImageForParameters, id, parameters) {
1777 bool docked(wb$inDock(parameters));
1779 WBStringDrawingState labelState = {NULL, 0, @""
1780 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1782 stringDrawingState_ = &labelState;
1785 UIImage *image(MSOldCall(parameters));
1788 stringDrawingState_ = NULL;
1793 MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1794 if ((self = MSOldCall(frame, delegate)) != nil) {
1795 [self setBackgroundColor:[UIColor clearColor]];
1799 MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1800 return SMSBackgrounded_ ? NO : MSOldCall();
1803 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1804 [self wb$setBackgroundColor:[UIColor clearColor]];
1808 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1810 [balloon setBackgroundColor:[UIColor clearColor]];
1813 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1814 MSOldCall([UIColor clearColor]);
1815 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1819 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1820 if ((self = MSOldCall(style, reuse)) != nil) {
1821 [self setBackgroundColor:[UIColor clearColor]];
1822 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1827 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1828 if ((self = MSOldCall(style, reuse)) != nil) {
1829 [self setBackgroundColor:[UIColor clearColor]];
1830 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1834 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1835 if ((self = MSOldCall(style, reuse)) != nil) {
1836 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1837 [_label setBackgroundColor:[UIColor clearColor]];
1841 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1842 MSOldCall(UITableViewCellSeparatorStyleNone);
1845 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1846 if ((self = MSOldCall(frame, style)) != nil) {
1847 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1851 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1854 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1855 if (UIImage *image = $getImage$(path)) {
1856 SMSBackgrounded_ = true;
1858 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1859 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1861 if (&_transcriptTable != NULL)
1862 table = _transcriptTable;
1863 else if (&_transcriptLayer != NULL)
1864 table = _transcriptLayer;
1868 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1869 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1872 [placard insertSubview:background atIndex:0];
1874 [table setBackgroundColor:[UIColor clearColor]];
1875 [placard insertSubview:background belowSubview:table];
1881 // %hook _UIImageWithName() {{{
1882 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1884 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1891 if (_UIPackedImageTableGetIdentifierForName != NULL)
1892 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1893 else if (_UISharedImageNameGetIdentifier != NULL) {
1894 identifier = _UISharedImageNameGetIdentifier(name);
1895 packed = identifier != -1;
1902 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1905 return __UIImageWithName(name);
1907 NSNumber *key([NSNumber numberWithInt:identifier]);
1908 UIImage *image([UIImages_ objectForKey:key]);
1910 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1911 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1912 image = $getImage$(path);
1913 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1917 image = __UIImageWithName(name);
1920 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1921 if (![Manager_ fileExistsAtPath:path])
1922 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1929 // %hook _UIImageWithNameInDomain() {{{
1930 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1931 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1932 UIImage *image([PathImages_ objectForKey:key]);
1934 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1936 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1937 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1938 image = $getImage$(path);
1939 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1940 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1944 // %hook GSFontCreateWithName() {{{
1945 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1947 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1948 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1949 name = [font UTF8String];
1950 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1951 // size *= [scale floatValue];
1952 return _GSFontCreateWithName(name, traits, size);
1956 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1957 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1959 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1961 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1963 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1964 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1966 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1969 NSString *path = [NSString stringWithUTF8String:a1];
1970 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1971 NSString *file = [path substringFromIndex:31];
1972 for (NSString *theme in Themes_) {
1973 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1974 if ([Manager_ fileExistsAtPath:path]) {
1975 strcpy(a1, [path UTF8String]);
1984 static void ChangeWallpaper(
1985 CFNotificationCenterRef center,
1989 CFDictionaryRef info
1992 NSLog(@"WB:Debug:ChangeWallpaper!");
1995 if (WallpaperFile_ != nil) {
1996 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1998 image = [image autorelease];
2001 if (WallpaperImage_ != nil)
2002 [WallpaperImage_ setImage:image];
2003 if (WallpaperPage_ != nil)
2004 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
2008 #define WBRename(name, sel, imp) \
2009 MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp, &_ ## name ## $ ## imp)
2011 template <typename Type_>
2012 static void msset(Type_ &function, MSImageRef image, const char *name) {
2013 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
2016 template <typename Type_>
2017 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
2018 struct nlist &name(nl[index]);
2019 uintptr_t value(name.n_value);
2020 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
2021 value |= 0x00000001;
2022 function = reinterpret_cast<Type_>(value);
2025 template <typename Type_>
2026 static void dlset(Type_ &function, const char *name) {
2027 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
2030 // %hook CGImageReadCreateWithFile() {{{
2031 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
2033 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
2034 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2035 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
2040 MSHook(void *, CGImageSourceCreateWithFile, NSString *path, NSDictionary *options) {
2042 NSLog(@"WB:Debug: CGImageSourceCreateWithFile(%@, %@)", path, options);
2043 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2044 void *value(_CGImageSourceCreateWithFile([path wb$themedPath], options));
2049 MSHook(void *, CGImageSourceCreateWithURL, NSURL *url, NSDictionary *options) {
2051 NSLog(@"WB:Debug: CGImageSourceCreateWithURL(%@, %@)", url, options);
2052 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2053 if ([url isFileURL])
2054 url = [NSURL fileURLWithPath:[[url path] wb$themedPath]];
2055 void *value(_CGImageSourceCreateWithURL(url, options));
2061 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
2062 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
2063 if (style == nil || [style length] == 0)
2064 style = @"font-family: Helvetica; font-size: 12px";
2065 //NSLog(@"XXX:drawP(%@ | %@)", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
2066 [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
2069 static void NSString$drawInRect$withStyle$(NSString *self, SEL _cmd, CGRect rect, NSString *style) {
2070 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
2071 if (style == nil || [style length] == 0)
2072 style = @"font-family: Helvetica; font-size: 12px";
2073 //NSLog(@"XXX:drawR(%@ | %@)", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
2074 return [[WBMarkup sharedMarkup] drawString:self inRect:rect withStyle:style];
2077 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
2078 if (style == nil || [style length] == 0)
2079 style = @"font-family: Helvetica; font-size: 12px";
2080 CGSize size([[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width]);
2081 //NSLog(@"XXX:size(%@ | %@) = [%g %g]", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "], size.width, size.height);
2085 static void SBInitialize() {
2087 WBRename(SBApplication, pathForIcon, pathForIcon);
2088 WBRename(SBApplicationIcon, icon, icon);
2089 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
2092 WBRename(SBBookmarkIcon, icon, icon);
2093 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
2094 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
2095 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
2096 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
2098 WBRename(SBWidgetApplicationIcon, icon, icon);
2100 WBRename(SBDockIconListView, setFrame:, setFrame$);
2101 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
2103 if (kCFCoreFoundationVersionNumber < 600 || SummerBoard_)
2104 WBRename(SBIconLabel, drawRect:, drawRect$);
2105 else if (kCFCoreFoundationVersionNumber < 700) {
2106 WBRename(SBIconLabel, buildLabelImage, buildLabelImage);
2108 WBRename(SBIconLabelImageParameters, hash, hash);
2109 WBRename($SBIconView, _labelImageParametersForIcon:location:, _labelImageParametersForIcon$location$);
2110 WBRename($SBIconLabelImage, _drawLabelImageForParameters:, _drawLabelImageForParameters$);
2113 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
2114 WBRename(SBIconLabel, setInDock:, setInDock$);
2116 WBRename(SBIconList, didMoveToSuperview, didMoveToSuperview);
2117 WBRename(SBIconList, setFrame:, setFrame$);
2119 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
2120 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
2121 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
2122 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
2124 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
2125 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
2126 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
2128 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
2130 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
2131 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
2132 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
2133 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
2134 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
2135 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
2136 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
2137 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
2138 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
2141 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
2144 /*MSHook(int, open, const char *path, int oflag, mode_t mode) {
2145 int fd(_open(path, oflag, mode));
2147 static bool no(false);
2151 if (strstr(path, "/icon") != NULL)
2152 MSHookProcess(-1, "");
2154 if (fd == -1 && errno == EFAULT)
2155 NSLog(@"open(%p, %#x, %#o) = %d\n", path, oflag, mode, fd);
2157 NSLog(@"open(\"%s\", %#x, %#o) = %d\n", path, oflag, mode, fd);
2164 $objc_setAssociatedObject = reinterpret_cast<void (*)(id, void *, id value, objc_AssociationPolicy)>(dlsym(RTLD_DEFAULT, "objc_setAssociatedObject"));
2165 $objc_getAssociatedObject = reinterpret_cast<id (*)(id, void *)>(dlsym(RTLD_DEFAULT, "objc_getAssociatedObject"));
2166 $objc_removeAssociatedObjects = reinterpret_cast<void (*)(id)>(dlsym(RTLD_DEFAULT, "objc_removeAssociatedObjects"));
2168 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2170 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
2171 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
2173 Manager_ = [[NSFileManager defaultManager] retain];
2174 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
2176 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
2178 // Load Settings.plist {{{
2179 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
2180 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
2181 SummerBoard_ = [value boolValue];
2183 SummerBoard_ = true;
2185 if (NSNumber *value = [settings objectForKey:@"Debug"])
2186 Debug_ = [value boolValue];
2187 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
2188 UIDebug_ = [value boolValue];
2190 NSArray *themes([settings objectForKey:@"Themes"]);
2192 if (NSString *theme = [settings objectForKey:@"Theme"])
2193 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
2195 [NSNumber numberWithBool:true], @"Active",
2199 for (NSDictionary *theme in themes) {
2200 NSNumber *active([theme objectForKey:@"Active"]);
2201 if (![active boolValue])
2204 NSString *name([theme objectForKey:@"Name"]);
2208 NSString *theme(nil);
2210 #define testForTheme(format...) \
2211 if (theme == nil) { \
2212 NSString *path = [NSString stringWithFormat:format]; \
2213 if ([Manager_ fileExistsAtPath:path]) { \
2214 [Themes_ addObject:path]; \
2219 testForTheme(@"/Library/Themes/%@.theme", name)
2220 testForTheme(@"/Library/Themes/%@", name)
2221 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
2226 // Merge Info.plist {{{
2227 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2229 for (NSString *theme in Themes_)
2230 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
2231 for (NSString *key in [info allKeys])
2232 if ([Info_ objectForKey:key] == nil)
2233 [Info_ setObject:[info objectForKey:key] forKey:key];
2237 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
2238 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
2239 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
2242 // GraphicsServices {{{
2244 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
2248 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
2249 void *(*CGImageReadCreateWithFile)(NSString *, int);
2250 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
2251 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
2253 if (CGImageReadCreateWithFile == NULL) {
2254 void *(*CGImageSourceCreateWithFile)(NSString *, NSDictionary *);
2255 msset(CGImageSourceCreateWithFile, image, "_CGImageSourceCreateWithFile");
2256 MSHookFunction(CGImageSourceCreateWithFile, MSHake(CGImageSourceCreateWithFile));
2258 void *(*CGImageSourceCreateWithURL)(NSURL *, NSDictionary *);
2259 msset(CGImageSourceCreateWithURL, image, "_CGImageSourceCreateWithURL");
2260 MSHookFunction(CGImageSourceCreateWithURL, MSHake(CGImageSourceCreateWithURL));
2266 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
2267 Papered_ = $getTheme$(Wallpapers_) != nil;
2268 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
2270 CFNotificationCenterAddObserver(
2271 CFNotificationCenterGetDarwinNotifyCenter(),
2272 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
2275 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
2276 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
2277 if (MediaPlayer != nil)
2280 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
2281 $MPVideoView = objc_getClass("MPVideoView");
2288 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
2289 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
2290 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v28@0:4{CGRect={CGSize=ff}{CGSize=ff}}8@24");
2291 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
2294 memset(nl, 0, sizeof(nl));
2295 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
2296 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
2297 nl[2].n_un.n_name = (char *) "__UIKitBundle";
2298 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
2299 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
2302 nlset(_UIApplicationImageWithName, nl, 0);
2303 nlset(_UIImageWithNameInDomain, nl, 1);
2304 nlset(_UIKitBundle, nl, 2);
2305 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
2306 nlset(_UISharedImageNameGetIdentifier, nl, 4);
2308 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
2309 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
2310 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
2314 //MSHookFunction(reinterpret_cast<int (*)(const char *, int, mode_t)>(&open), MSHake(open));
2316 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
2317 NSError *error(nil);
2318 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
2319 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
2321 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);