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]];
380 remapResourceName(@"FSO_BG.png", @"StatusBar")
381 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
382 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
384 [names addObject:[NSString stringWithFormat:@"Fallback/%@", file]];
386 if (NSString *path = $getTheme$($useScale$(names, ui)))
393 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
394 NSString *identifier = [self bundleIdentifier];
395 NSString *path = [self path];
396 NSString *folder = [path lastPathComponent];
397 NSString *dname = [self displayName];
398 NSString *didentifier = [self displayIdentifier];
401 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
403 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
405 /* XXX: I might need to keep this for backwards compatibility
406 if (identifier != nil)
407 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
409 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
411 #define testForIcon(Name) \
412 if (NSString *name = Name) \
413 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
415 if (![didentifier isEqualToString:identifier])
416 testForIcon(didentifier);
418 testForIcon(identifier);
421 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
424 if (didentifier != nil) {
425 testForIcon([English_ objectForKey:didentifier]);
427 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
428 if ([parts count] != 1)
429 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
430 testForIcon([english objectForKey:[parts lastObject]]);
433 if (NSString *path = $getTheme$(names))
439 // -[NSBundle wb$bundleWithFile] {{{
440 @interface NSBundle (WinterBoard)
441 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
444 @implementation NSBundle (WinterBoard)
446 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
447 path = [path stringByDeletingLastPathComponent];
448 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
451 NSBundle *bundle([Bundles_ objectForKey:path]);
452 if (reinterpret_cast<id>(bundle) == [NSNull null])
454 else if (bundle == nil) {
455 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
456 bundle = [NSBundle bundleWithPath:path];
458 bundle = [NSBundle wb$bundleWithFile:path];
460 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
461 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
469 // -[NSString wb$themedPath] {{{
470 @interface NSString (WinterBoard)
471 - (NSString *) wb$themedPath;
474 @implementation NSString (WinterBoard)
476 - (NSString *) wb$themedPath {
477 if ([self hasPrefix:@"/Library/Themes/"])
481 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
483 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
484 NSString *file([self stringByResolvingSymlinksInPath]);
485 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
486 if ([file hasPrefix:prefix]) {
487 NSUInteger length([prefix length]);
488 if (length != [file length])
489 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
500 void WBLogRect(const char *tag, struct CGRect rect) {
501 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
504 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
505 CGRect frame([view frame]);
506 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]);
508 for (UIView *child in [view subviews])
509 WBLogHierarchy(child, index++, indent + 1);
512 UIImage *$cacheForImage$(UIImage *image) {
513 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
514 CGRect rect = {CGPointMake(1, 1), [image size]};
515 CGSize size = {rect.size.width + 2, rect.size.height + 2};
517 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
518 CGColorSpaceRelease(space);
520 CGContextDrawImage(context, rect, [image CGImage]);
521 CGImageRef ref(CGBitmapContextCreateImage(context));
522 CGContextRelease(context);
524 UIImage *cache([UIImage imageWithCGImage:ref]);
530 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
531 //if ([name isEqualToString:@"icons"]) return nil;
532 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
535 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
536 NSString *key([icon displayIdentifier]);
538 if (UIImage *image = [icon icon]) {
539 CGSize size = [image size];
540 if (size.width != 59 || size.height != 60) {
541 UIImage *cache($cacheForImage$(image));
542 [Cache_ setObject:cache forKey:key];
547 _SBIconModel$cacheImageForIcon$(self, sel, icon);
550 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
551 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
552 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
554 NSString *key([icon displayIdentifier]);
556 if (UIImage *image = [icon icon]) {
557 CGSize size = [image size];
558 if (size.width != 59 || size.height != 60) {
559 UIImage *cache($cacheForImage$(image));
560 [Cache_ setObject:cache forKey:key];
566 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
567 NSString *key([icon displayIdentifier]);
568 if (UIImage *image = [Cache_ objectForKey:key])
571 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
574 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
576 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
577 NSString *key([icon displayIdentifier]);
578 if (UIImage *image = [Cache_ objectForKey:key])
581 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
584 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
585 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
586 [self setBackgroundColor:[UIColor clearColor]];
587 for (UIView *child in [self subviews])
588 [child setBackgroundColor:[UIColor clearColor]];
592 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
593 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
594 [self setBackgroundColor:[UIColor clearColor]];
598 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
599 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
600 float inset([self edgeInset]);
601 [[UIColor clearColor] set];
602 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
603 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
606 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
607 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
608 if (NSString *path = $pathForIcon$([self application]))
609 return [UIImage imageWithContentsOfFile:path];
610 return _SBApplicationIcon$icon(self, sel);
613 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
615 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
616 if (IsWild_ && false) // XXX: delete this code, it should not be supported
617 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
618 return [UIImage imageWithContentsOfFile:path72];
619 if (NSString *path = $pathForIcon$([self application]))
620 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
622 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
623 width = [$SBIcon defaultIconImageSize].width;
626 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
629 return _SBApplicationIcon$generateIconImage$(self, sel, type);
632 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
634 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
635 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
636 return [UIImage imageWithContentsOfFile:path];
637 return _SBWidgetApplicationIcon$icon(self, sel);
640 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
642 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
643 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
644 return [UIImage imageWithContentsOfFile:path];
645 return _SBBookmarkIcon$icon(self, sel);
648 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
649 if (NSString *path = $pathForIcon$(self))
651 return _SBApplication$pathForIcon(self, sel);
654 static UIImage *CachedImageAtPath(NSString *path) {
655 path = [path stringByResolvingSymlinksInPath];
656 UIImage *image = [PathImages_ objectForKey:path];
658 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
659 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
661 image = [image autorelease];
662 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
666 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
667 NSBundle *bundle = [NSBundle mainBundle];
669 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
670 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
671 return CachedImageAtPath(path);
672 return __UIApplicationImageWithName(name);
675 #define WBDelegate(delegate) \
676 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
678 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
679 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
681 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
685 - (void) forwardInvocation:(NSInvocation*)inv { \
686 SEL sel = [inv selector]; \
687 if ([delegate respondsToSelector:sel]) \
688 [inv invokeWithTarget:delegate]; \
690 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
693 // %hook -[NSBundle pathForResource:ofType:] {{{
694 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
695 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
697 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
698 if (NSString *path = $pathForFile$inBundle$(file, self, false))
700 return MSOldCall(resource, type);
704 static void $drawLabel$(NSString *label, CGRect rect, NSString *style, NSString *custom) {
705 bool ellipsis(false);
706 float max = rect.size.width - 11, width;
708 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
711 size_t length([label length]);
712 float spacing((width - max) / (length - 1));
714 if (spacing > 1.25) {
716 label = [label substringToIndex:(length - 1)];
720 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
724 label = [label stringByAppendingString:@"..."];
727 style = [style stringByAppendingString:custom];
729 CGSize size = [label sizeWithStyle:style forWidth:rect.size.width];
730 [label drawAtPoint:CGPointMake((rect.size.width - size.width) / 2 + rect.origin.x, rect.origin.y) withStyle:style];
733 static struct WBStringDrawingState {
734 WBStringDrawingState *next_;
738 } *stringDrawingState_;
740 extern "C" CGColorSpaceRef CGContextGetFillColorSpace(CGContextRef);
741 extern "C" void CGContextGetFillColor(CGContextRef, CGFloat[]);
743 static NSString *WBColorMarkup() {
744 CGContextRef context(UIGraphicsGetCurrentContext());
745 //NSLog(@"XXX:1:%p", context);
749 CGColorSpaceRef space(CGContextGetFillColorSpace(context));
750 //NSLog(@"XXX:2:%p", space);
754 size_t number(CGColorSpaceGetNumberOfComponents(space));
755 //NSLog(@"XXX:3:%u", number);
759 CGFloat components[number + 1];
760 CGContextGetFillColor(context, components);
783 return [NSString stringWithFormat:@"color: rgba(%g, %g, %g, %g)", r * 255, g * 255, b * 255, a];
786 MSInstanceMessageHook6(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode,letterSpacing,includeEmoji, CGPoint, point, float, width, UIFont *, font, UILineBreakMode, mode, float, spacing, BOOL, emoji) {
787 //NSLog(@"XXX: @\"%@\" %g", self, spacing);
789 WBStringDrawingState *state(stringDrawingState_);
791 return MSOldCall(point, width, font, mode, spacing, emoji);
793 if (--state->count_ == 0)
794 stringDrawingState_ = state->next_;
795 if (state->info_ == nil)
796 return MSOldCall(point, width, font, mode, spacing, emoji);
798 NSString *info([Info_ objectForKey:state->info_]);
800 return MSOldCall(point, width, font, mode, spacing, emoji);
802 NSString *base(state->base_ ?: @"");
803 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
804 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
808 extern "C" NSString *NSStringFromCGRect(CGRect rect);
810 MSInstanceMessageHook7(CGSize, NSString, _drawInRect,withFont,lineBreakMode,alignment,lineSpacing,includeEmoji,truncationRect, CGRect, rect, UIFont *, font, UILineBreakMode, mode, UITextAlignment, alignment, float, spacing, BOOL, emoji, CGRect, truncation) {
811 //NSLog(@"XXX: &\"%@\" %@ \"%@\" %u %u %g %u %@", self, NSStringFromCGRect(rect), font, mode, alignment, spacing, emoji, NSStringFromCGRect(truncation));
813 WBStringDrawingState *state(stringDrawingState_);
815 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
817 if (--state->count_ == 0)
818 stringDrawingState_ = state->next_;
819 if (state->info_ == nil)
820 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
822 NSString *info([Info_ objectForKey:state->info_]);
824 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
829 case UITextAlignmentLeft:
832 case UITextAlignmentCenter:
833 textAlign = @"center";
835 case UITextAlignmentRight:
836 textAlign = @"right";
840 NSString *base(state->base_ ?: @"");
841 NSString *extra([NSString stringWithFormat:@"text-align: %@", textAlign]);
844 $drawLabel$(self, rect, [NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], WBColorMarkup(), base], info);
846 [self drawInRect:rect withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
851 MSInstanceMessageHook4(CGSize, NSString, sizeWithFont,forWidth,lineBreakMode,letterSpacing, UIFont *, font, float, width, UILineBreakMode, mode, float, spacing) {
852 //NSLog(@"XXX: #\"%@\" \"%@\" %g %u %g", self, font, width, mode, spacing);
854 WBStringDrawingState *state(stringDrawingState_);
856 return MSOldCall(font, width, mode, spacing);
858 if (--state->count_ == 0)
859 stringDrawingState_ = state->next_;
860 if (state->info_ == nil)
861 return MSOldCall(font, width, mode, spacing);
863 NSString *info([Info_ objectForKey:state->info_]);
865 return MSOldCall(font, width, mode, spacing);
867 NSString *base(state->base_ ?: @"");
868 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
869 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info] forWidth:width];
872 MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) {
873 //NSLog(@"XXX: ?\"%@\"", self);
875 WBStringDrawingState *state(stringDrawingState_);
877 return MSOldCall(font);
879 if (--state->count_ == 0)
880 stringDrawingState_ = state->next_;
881 if (state->info_ == nil)
882 return MSOldCall(font);
884 NSString *info([Info_ objectForKey:state->info_]);
886 return MSOldCall(font);
888 NSString *base(state->base_ ?: @"");
889 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), base, info] forWidth:65535];
892 MSClassMessageHook2(UIImage *, SBIconAccessoryImage, checkoutAccessoryImageForIcon,location, id, icon, int, location) {
893 if ([self _imageClassForIcon:icon location:location] != $SBIconBadgeImage)
894 return MSOldCall(icon, location);
896 WBStringDrawingState badgeState = {NULL, -1, @""
899 stringDrawingState_ = &badgeState;
901 UIImage *image(MSOldCall(icon, location));
903 stringDrawingState_ = NULL;
907 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
908 WBStringDrawingState badgeState = {NULL, -1, @""
911 stringDrawingState_ = &badgeState;
913 UIImage *image(MSOldCall(text));
915 stringDrawingState_ = NULL;
919 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
920 WBStringDrawingState dayState = {NULL, 2, @""
921 // XXX: this is only correct on an iPod dock
922 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
923 , @"CalendarIconDayStyle"};
925 WBStringDrawingState sizeState = {&dayState, 7, nil, nil};
927 WBStringDrawingState dateState = {&sizeState, 2, @""
928 , @"CalendarIconDateStyle"};
930 stringDrawingState_ = &dateState;
932 UIImage *image(MSOldCall(type));
934 stringDrawingState_ = NULL;
938 MSInstanceMessageHook1(UIImage *, UIStatusBarTimeItemView, contentsImageForStyle, int, style) {
939 WBStringDrawingState timeState = {NULL, 0, @""
942 stringDrawingState_ = &timeState;
944 UIImage *image(MSOldCall(style));
946 stringDrawingState_ = NULL;
950 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
951 NSBundle *bundle([NSBundle mainBundle]);
953 CFLocaleRef locale(CFLocaleCopyCurrent());
954 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
957 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
959 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
960 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
961 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
962 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
966 CFRelease(formatter);
968 NSString *datestyle([@""
969 "font-family: Helvetica; "
970 "font-weight: bold; "
973 "" stringByAppendingString:(IsWild_
974 ? @"font-size: 54px; "
975 : @"font-size: 39px; "
978 NSString *daystyle([@""
979 "font-family: Helvetica; "
980 "font-weight: bold; "
982 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
983 "" stringByAppendingString:(IsWild_
984 ? @"font-size: 11px; "
985 : @"font-size: 9px; "
988 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
989 datestyle = [datestyle stringByAppendingString:style];
990 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
991 daystyle = [daystyle stringByAppendingString:style];
993 float width([self bounds].size.width);
995 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
996 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
998 unsigned base0(IsWild_ ? 89 : 70);
999 if ($GSFontGetUseLegacyFontMetrics())
1001 unsigned base1(IsWild_ ? 18 : 16);
1008 [(NSString *)date drawAtPoint:CGPointMake(
1009 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
1010 ) withStyle:datestyle];
1012 [(NSString *)day drawAtPoint:CGPointMake(
1013 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
1014 ) withStyle:daystyle];
1020 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
1021 void $setBarStyle$_(NSString *name, int &style) {
1023 NSLog(@"WB:Debug:%@Style:%d", name, style);
1024 NSNumber *number = nil;
1026 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
1028 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
1029 if (number != nil) {
1030 style = [number intValue];
1032 NSLog(@"WB:Debug:%@Style=%d", name, style);
1036 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
1037 $setBarStyle$_(@"Toolbar", style);
1038 return MSOldCall(style);
1041 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
1042 $setBarStyle$_(@"NavigationBar", style);
1043 return MSOldCall(style);
1047 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
1048 [[self superview] setBackgroundColor:[UIColor clearColor]];
1049 _SBButtonBar$didMoveToSuperview(self, sel);
1052 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
1053 [[self superview] setBackgroundColor:[UIColor clearColor]];
1054 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
1057 static NSArray *Wallpapers_;
1058 static bool Papered_;
1059 static bool Docked_;
1060 static bool SMSBackgrounded_;
1061 static NSString *WallpaperFile_;
1062 static UIImageView *WallpaperImage_;
1063 static UIWebDocumentView *WallpaperPage_;
1064 static NSURL *WallpaperURL_;
1066 #define _release(object) \
1067 do if (object != nil) { \
1072 static UIImage *$getImage$(NSString *path) {
1073 UIImage *image([UIImage imageWithContentsOfFile:path]);
1075 unsigned scale($getScale$(path));
1076 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
1077 [image setScale:scale];
1082 static UIImage *$getDefaultDesktopImage$() {
1083 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
1084 return $getImage$(path);
1088 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
1089 return $getDefaultDesktopImage$() ?: MSOldCall();
1092 MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
1093 return $getDefaultDesktopImage$() ?: MSOldCall();
1096 MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
1097 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
1098 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
1099 if (UIImage *image = $getDefaultDesktopImage$()) {
1100 [self setImage:image];
1110 // %hook -[SBUIController init] {{{
1111 MSInstanceMessageHook0(id, SBUIController, init) {
1116 NSString *paper($getTheme$(Wallpapers_));
1118 paper = [paper stringByDeletingLastPathComponent];
1122 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
1123 char *machine = new char[size];
1125 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
1126 perror("sysctlbyname(\"hw.machine\", ?)");
1131 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
1135 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
1138 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
1139 if (&_wallpaperView != NULL) {
1140 [_wallpaperView removeFromSuperview];
1141 [_wallpaperView release];
1142 _wallpaperView = nil;
1146 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
1147 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
1150 if (&_contentLayer != NULL)
1151 player = &_contentLayer;
1152 else if (&_contentView != NULL)
1153 player = &_contentView;
1156 UIView *layer(player == NULL ? nil : *player);
1158 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
1159 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
1160 [window setContentView:content];
1162 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
1163 [window setBackgroundColor:[_window backgroundColor]];
1164 [_window setBackgroundColor:[UIColor clearColor]];
1166 [window setLevel:-1000];
1167 [window setHidden:NO];
1169 /*if (player != NULL)
1170 *player = content;*/
1172 [content setBackgroundColor:[layer backgroundColor]];
1173 [layer setBackgroundColor:[UIColor clearColor]];
1176 if (!SummerBoard_ || !IsWild_)
1179 CGRect bounds([content bounds]);
1180 bounds.origin.y = -30;
1181 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
1182 [content addSubview:indirect];
1183 [indirect zoomToScale:2.4];
1186 _release(WallpaperFile_);
1187 _release(WallpaperImage_);
1188 _release(WallpaperPage_);
1189 _release(WallpaperURL_);
1192 NSArray *themes([NSArray arrayWithObject:paper]);
1194 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1198 static AVController *controller_(nil);
1199 if (controller_ == nil) {
1200 AVQueue *queue([AVQueue avQueue]);
1201 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1204 AVQueue *queue([controller_ queue]);
1206 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1207 [controller_ setLayer:[video _layer]];
1209 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1210 [queue appendItem:item error:&error];
1212 [controller_ play:&error];
1213 #elif UseMPMoviePlayerController
1214 NSURL *url([NSURL fileURLWithPath:path]);
1215 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1216 controller.movieControlMode = MPMovieControlModeHidden;
1219 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1220 [video setMovieWithPath:path];
1221 [video setRepeatMode:1];
1222 [video setRepeatGap:-1];
1223 [video playFromBeginning];;
1226 [indirect addSubview:video];
1229 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1230 if (UIImage *image = $getImage$(path)) {
1231 WallpaperFile_ = [path retain];
1232 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1233 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1234 [WallpaperImage_ setAlpha:[number floatValue]];
1235 [indirect addSubview:WallpaperImage_];
1239 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1240 CGRect bounds = [indirect bounds];
1242 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1243 [view setAutoresizes:true];
1245 WallpaperPage_ = [view retain];
1246 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1248 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1250 [view setBackgroundColor:[UIColor clearColor]];
1251 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1252 [view setDrawsBackground:NO];
1253 [[view webView] setDrawsBackground:NO];
1255 [indirect addSubview:view];
1259 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1260 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1261 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1262 if ([Manager_ fileExistsAtPath:html]) {
1263 CGRect bounds = [indirect bounds];
1265 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1266 [view setAutoresizes:true];
1268 NSURL *url = [NSURL fileURLWithPath:html];
1269 [view loadRequest:[NSURLRequest requestWithURL:url]];
1271 [view setBackgroundColor:[UIColor clearColor]];
1272 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1273 [view setDrawsBackground:NO];
1274 [[view webView] setDrawsBackground:NO];
1276 [indirect addSubview:view];
1284 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1285 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1286 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1288 if (path != nil && _backgroundView != nil)
1291 _SBAwayView$updateDesktopImage$(self, sel, image);
1294 CGRect bounds = [self bounds];
1296 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1297 [view setAutoresizes:true];
1299 if (WallpaperPage_ != nil)
1300 [WallpaperPage_ release];
1301 WallpaperPage_ = [view retain];
1303 if (WallpaperURL_ != nil)
1304 [WallpaperURL_ release];
1305 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1307 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1309 [[view webView] setDrawsBackground:false];
1310 [view setBackgroundColor:[UIColor clearColor]];
1312 [self insertSubview:view aboveSubview:_backgroundView];
1316 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1317 extern "C" CGColorRef CGGStateGetFillColor(void *);
1318 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1319 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1321 /* WBTimeLabel {{{ */
1322 @interface WBTimeLabel : NSProxy {
1324 _transient SBStatusBarTimeView *view_;
1327 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1331 @implementation WBTimeLabel
1338 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1339 time_ = [time retain];
1344 - (NSString *) description {
1350 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1351 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1352 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1354 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1355 "font-family: Helvetica; "
1356 "font-weight: bold; "
1359 "%@", _mode ? @"white" : @"black", custom]];
1364 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1369 /* WBBadgeLabel {{{ */
1370 @interface WBBadgeLabel : NSProxy {
1374 - (id) initWithBadge:(NSString *)badge;
1375 - (NSString *) description;
1379 @implementation WBBadgeLabel
1386 - (id) initWithBadge:(NSString *)badge {
1387 badge_ = [badge retain];
1391 - (NSString *) description {
1392 return [badge_ description];
1397 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1398 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1399 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1400 "font-family: Helvetica; "
1401 "font-weight: bold; "
1409 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1416 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1417 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1418 alpha = [number floatValue];
1419 return MSOldCall(alpha);
1422 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1423 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1424 alpha = [number floatValue];
1425 return MSOldCall(alpha);
1428 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1429 if ((self = MSOldCall()) != nil) {
1430 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1431 // XXX: note: this is overridden above, which is silly
1432 float alpha([number floatValue]);
1433 if ([self respondsToSelector:@selector(setIconImageAlpha:)])
1434 [self setIconImageAlpha:alpha];
1435 if ([self respondsToSelector:@selector(setIconLabelAlpha:)])
1436 [self setIconLabelAlpha:alpha];
1437 if ([self respondsToSelector:@selector(setAlpha:)])
1438 [self setAlpha:alpha];
1443 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1444 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1445 alpha = [number floatValue];
1446 return MSOldCall(alpha);
1450 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1451 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1452 id &_badge(MSHookIvar<id>(self, "_badge"));
1454 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1459 void SBStatusBarController$setStatusBarMode(int &mode) {
1461 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1462 if (mode < 100) // 104:hidden 105:glowing
1463 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1464 mode = [number intValue];
1467 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1468 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1469 SBStatusBarController$setStatusBarMode(mode);
1470 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1473 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1474 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1475 SBStatusBarController$setStatusBarMode(mode);
1476 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1479 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) {
1480 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1481 SBStatusBarController$setStatusBarMode(mode);
1482 //NSLog(@"mode=%u", mode);
1483 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1486 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1487 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1488 mode = [number intValue];
1489 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1492 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1493 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1495 NSLog(@"operatorNameStyle= %@", style);
1496 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1497 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1501 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1503 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1504 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1507 // XXX: replace this with [SBStatusBarTimeView tile]
1508 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1509 id &_time(MSHookIvar<id>(self, "_time"));
1510 if (_time != nil && [_time class] != [WBTimeLabel class])
1511 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1512 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1515 @interface UIView (WinterBoard)
1516 - (bool) wb$isWBImageView;
1517 - (void) wb$logHierarchy;
1518 - (void) wb$setBackgroundColor:(UIColor *)color;
1521 @implementation UIView (WinterBoard)
1523 - (bool) wb$isWBImageView {
1527 - (void) wb$logHierarchy {
1528 WBLogHierarchy(self);
1531 - (void) wb$setBackgroundColor:(UIColor *)color {
1532 [self setBackgroundColor:color];
1533 for (UIView *child in [self subviews])
1534 [child wb$setBackgroundColor:color];
1539 @interface WBImageView : UIImageView {
1542 - (bool) wb$isWBImageView;
1543 - (void) wb$updateFrame;
1546 @implementation WBImageView
1548 - (bool) wb$isWBImageView {
1552 - (void) wb$updateFrame {
1553 CGRect frame([self frame]);
1556 for (UIView *view(self); ; ) {
1557 view = [view superview];
1560 frame.origin.y -= [view frame].origin.y;
1563 [self setFrame:frame];
1568 static void SBIconList$updateFrames$(SBIconList *self) {
1569 NSArray *subviews([self subviews]);
1570 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1571 if (view != nil && [view wb$isWBImageView])
1572 [view wb$updateFrame];
1575 MSHook(void, SBIconList$didMoveToSuperview, SBIconList *self, SEL sel) {
1576 SBIconList$updateFrames$(self);
1577 _SBIconList$didMoveToSuperview(self, sel);
1580 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1581 SBIconList$updateFrames$(self);
1582 _SBIconList$setFrame$(self, sel, frame);
1585 static void $addPerPageView$(unsigned i, UIView *list) {
1586 NSString *path($getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]]));
1590 NSArray *subviews([list subviews]);
1592 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1593 if (view == nil || ![view wb$isWBImageView]) {
1594 view = [[[WBImageView alloc] init] autorelease];
1595 [list insertSubview:view atIndex:0];
1598 UIImage *image([UIImage imageWithContentsOfFile:path]);
1600 CGRect frame([view frame]);
1601 frame.size = [image size];
1602 [view setFrame:frame];
1604 [view setImage:image];
1605 [view wb$updateFrame];
1608 static void $addPerPageViews$(NSArray *lists) {
1609 for (unsigned i(0), e([lists count]); i != e; ++i)
1610 $addPerPageView$(i, [lists objectAtIndex:i]);
1613 MSInstanceMessageHook0(void, SBIconController, updateNumberOfRootIconLists) {
1614 NSArray *&_rootIconLists(MSHookIvar<NSArray *>(self, "_rootIconLists"));
1615 $addPerPageViews$(_rootIconLists);
1619 MSInstanceMessageHook0(void, SBIconContentView, layoutSubviews) {
1622 if (SBIconController *controller = [$SBIconController sharedInstance]) {
1623 UIView *&_dockContainerView(MSHookIvar<UIView *>(controller, "_dockContainerView"));
1624 if (&_dockContainerView != NULL)
1625 [[_dockContainerView superview] bringSubviewToFront:_dockContainerView];
1629 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1630 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1631 $addPerPageViews$([_iconModel iconLists]);
1632 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1635 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1636 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1638 [self setClipsToBounds:NO];
1642 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1643 static bool gssc(false);
1645 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1646 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1649 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1650 [Info_ setObject:[NSNumber numberWithBool:(
1652 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1653 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1654 )] forKey:@"UndockedIconLabels"];
1657 id &_label(MSHookIvar<id>(self, "_label"));
1658 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1661 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1662 [_label setInDock:docked];
1664 _SBIconLabel$setInDock$(self, sel, docked);
1665 [self setNeedsDisplay];
1668 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1669 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1672 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1673 _SBDockIconListView$setFrame$(self, sel, frame);
1676 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1677 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1678 NSString *identifier = [self bundleIdentifier];
1679 NSLocale *locale = [NSLocale currentLocale];
1680 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1682 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1683 NSString *file = table == nil ? @"Localizable" : table;
1684 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1685 NSDictionary *strings;
1686 if ((strings = [Strings_ objectForKey:name]) != nil) {
1687 if (static_cast<id>(strings) != [NSNull null]) strings:
1688 if (NSString *value = [strings objectForKey:key])
1690 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1693 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1694 [Strings_ setObject:[strings autorelease] forKey:name];
1698 [Strings_ setObject:[NSNull null] forKey:name];
1699 return MSOldCall(key, value, table);
1702 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1703 MSClassHook(WebCoreFrameBridge)
1705 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1708 void **core(reinterpret_cast<void **>([node _node]));
1709 if (core == NULL || core[6] == NULL)
1711 return MSOldCall(node, width);
1715 MSInstanceMessage1(void, SBIconLabel, drawRect, CGRect, rect) {
1716 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1719 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1720 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1722 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1724 NSString *style = [NSString stringWithFormat:@""
1725 "font-family: Helvetica; "
1726 "font-weight: bold; "
1728 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1729 ? @"font-size: 12px; "
1730 : @"font-size: 11px; "
1734 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1736 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1738 NSString *custom([Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")]);
1740 $drawLabel$(label, [self bounds], style, custom);
1743 MSInstanceMessage0(CGImageRef, SBIconLabel, buildLabelImage) {
1744 bool docked((MSHookIvar<unsigned>(self, "_inDock") & 0x2) != 0);
1746 WBStringDrawingState labelState = {NULL, 0, @""
1747 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1749 stringDrawingState_ = &labelState;
1752 CGImageRef image(MSOldCall());
1755 stringDrawingState_ = NULL;
1759 static bool wb$inDock(id parameters) {
1760 return [$objc_getAssociatedObject(parameters, @selector(wb$inDock)) boolValue];
1763 MSInstanceMessage0(NSUInteger, SBIconLabelImageParameters, hash) {
1764 return MSOldCall() + (wb$inDock(self) ? 0xdeadbeef : 0xd15ea5e);
1767 MSClassMessage2(id, SBIconView, _labelImageParametersForIcon,location, id, icon, int, location) {
1768 if (id parameters = MSOldCall(icon, location)) {
1769 $objc_setAssociatedObject(parameters, @selector(wb$inDock), [NSNumber numberWithBool:(location == 1)], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1774 MSClassMessage1(UIImage *, SBIconLabelImage, _drawLabelImageForParameters, id, parameters) {
1775 bool docked(wb$inDock(parameters));
1777 WBStringDrawingState labelState = {NULL, 0, @""
1778 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1780 stringDrawingState_ = &labelState;
1783 UIImage *image(MSOldCall(parameters));
1786 stringDrawingState_ = NULL;
1791 MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1792 if ((self = MSOldCall(frame, delegate)) != nil) {
1793 [self setBackgroundColor:[UIColor clearColor]];
1797 MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1798 return SMSBackgrounded_ ? NO : MSOldCall();
1801 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1802 [self wb$setBackgroundColor:[UIColor clearColor]];
1806 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1808 [balloon setBackgroundColor:[UIColor clearColor]];
1811 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1812 MSOldCall([UIColor clearColor]);
1813 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1817 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1818 if ((self = MSOldCall(style, reuse)) != nil) {
1819 [self setBackgroundColor:[UIColor clearColor]];
1820 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1825 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1826 if ((self = MSOldCall(style, reuse)) != nil) {
1827 [self setBackgroundColor:[UIColor clearColor]];
1828 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1832 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1833 if ((self = MSOldCall(style, reuse)) != nil) {
1834 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1835 [_label setBackgroundColor:[UIColor clearColor]];
1839 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1840 MSOldCall(UITableViewCellSeparatorStyleNone);
1843 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1844 if ((self = MSOldCall(frame, style)) != nil) {
1845 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1849 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1852 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1853 if (UIImage *image = $getImage$(path)) {
1854 SMSBackgrounded_ = true;
1856 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1857 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1859 if (&_transcriptTable != NULL)
1860 table = _transcriptTable;
1861 else if (&_transcriptLayer != NULL)
1862 table = _transcriptLayer;
1866 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1867 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1870 [placard insertSubview:background atIndex:0];
1872 [table setBackgroundColor:[UIColor clearColor]];
1873 [placard insertSubview:background belowSubview:table];
1879 // %hook _UIImageWithName() {{{
1880 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1882 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1889 if (_UIPackedImageTableGetIdentifierForName != NULL)
1890 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1891 else if (_UISharedImageNameGetIdentifier != NULL) {
1892 identifier = _UISharedImageNameGetIdentifier(name);
1893 packed = identifier != -1;
1900 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1903 return __UIImageWithName(name);
1905 NSNumber *key([NSNumber numberWithInt:identifier]);
1906 UIImage *image([UIImages_ objectForKey:key]);
1908 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1909 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1910 image = $getImage$(path);
1911 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1915 image = __UIImageWithName(name);
1918 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1919 if (![Manager_ fileExistsAtPath:path])
1920 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1927 // %hook _UIImageWithNameInDomain() {{{
1928 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1929 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1930 UIImage *image([PathImages_ objectForKey:key]);
1932 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1934 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1935 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1936 image = $getImage$(path);
1937 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1938 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
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"
1955 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1957 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1959 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1961 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1962 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1964 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1967 NSString *path = [NSString stringWithUTF8String:a1];
1968 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1969 NSString *file = [path substringFromIndex:31];
1970 for (NSString *theme in Themes_) {
1971 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1972 if ([Manager_ fileExistsAtPath:path]) {
1973 strcpy(a1, [path UTF8String]);
1982 static void ChangeWallpaper(
1983 CFNotificationCenterRef center,
1987 CFDictionaryRef info
1990 NSLog(@"WB:Debug:ChangeWallpaper!");
1993 if (WallpaperFile_ != nil) {
1994 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1996 image = [image autorelease];
1999 if (WallpaperImage_ != nil)
2000 [WallpaperImage_ setImage:image];
2001 if (WallpaperPage_ != nil)
2002 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
2006 #define WBRename(name, sel, imp) \
2007 MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp, &_ ## name ## $ ## imp)
2009 template <typename Type_>
2010 static void msset(Type_ &function, MSImageRef image, const char *name) {
2011 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
2014 template <typename Type_>
2015 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
2016 struct nlist &name(nl[index]);
2017 uintptr_t value(name.n_value);
2018 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
2019 value |= 0x00000001;
2020 function = reinterpret_cast<Type_>(value);
2023 template <typename Type_>
2024 static void dlset(Type_ &function, const char *name) {
2025 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
2028 // %hook CGImageReadCreateWithFile() {{{
2029 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
2031 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
2032 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2033 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
2038 MSHook(void *, CGImageSourceCreateWithFile, NSString *path, NSDictionary *options) {
2040 NSLog(@"WB:Debug: CGImageSourceCreateWithFile(%@, %@)", path, options);
2041 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2042 void *value(_CGImageSourceCreateWithFile([path wb$themedPath], options));
2047 MSHook(void *, CGImageSourceCreateWithURL, NSURL *url, NSDictionary *options) {
2049 NSLog(@"WB:Debug: CGImageSourceCreateWithURL(%@, %@)", url, options);
2050 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2051 if ([url isFileURL])
2052 url = [NSURL fileURLWithPath:[[url path] wb$themedPath]];
2053 void *value(_CGImageSourceCreateWithURL(url, options));
2059 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
2060 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
2061 if (style == nil || [style length] == 0)
2062 style = @"font-family: Helvetica; font-size: 12px";
2063 //NSLog(@"XXX:drawP(%@ | %@)", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
2064 [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
2067 static void NSString$drawInRect$withStyle$(NSString *self, SEL _cmd, CGRect rect, NSString *style) {
2068 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
2069 if (style == nil || [style length] == 0)
2070 style = @"font-family: Helvetica; font-size: 12px";
2071 //NSLog(@"XXX:drawR(%@ | %@)", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
2072 return [[WBMarkup sharedMarkup] drawString:self inRect:rect withStyle:style];
2075 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
2076 if (style == nil || [style length] == 0)
2077 style = @"font-family: Helvetica; font-size: 12px";
2078 CGSize size([[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width]);
2079 //NSLog(@"XXX:size(%@ | %@) = [%g %g]", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "], size.width, size.height);
2083 static void SBInitialize() {
2085 WBRename(SBApplication, pathForIcon, pathForIcon);
2086 WBRename(SBApplicationIcon, icon, icon);
2087 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
2090 WBRename(SBBookmarkIcon, icon, icon);
2091 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
2092 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
2093 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
2094 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
2096 WBRename(SBWidgetApplicationIcon, icon, icon);
2098 WBRename(SBDockIconListView, setFrame:, setFrame$);
2099 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
2101 if (kCFCoreFoundationVersionNumber < 600 || SummerBoard_)
2102 WBRename(SBIconLabel, drawRect:, drawRect$);
2103 else if (kCFCoreFoundationVersionNumber < 700) {
2104 WBRename(SBIconLabel, buildLabelImage, buildLabelImage);
2106 WBRename(SBIconLabelImageParameters, hash, hash);
2107 WBRename($SBIconView, _labelImageParametersForIcon:location:, _labelImageParametersForIcon$location$);
2108 WBRename($SBIconLabelImage, _drawLabelImageForParameters:, _drawLabelImageForParameters$);
2111 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
2112 WBRename(SBIconLabel, setInDock:, setInDock$);
2114 WBRename(SBIconList, didMoveToSuperview, didMoveToSuperview);
2115 WBRename(SBIconList, setFrame:, setFrame$);
2117 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
2118 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
2119 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
2120 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
2122 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
2123 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
2124 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
2126 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
2128 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
2129 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
2130 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
2131 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
2132 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
2133 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
2134 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
2135 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
2136 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
2139 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
2143 $objc_setAssociatedObject = reinterpret_cast<void (*)(id, void *, id value, objc_AssociationPolicy)>(dlsym(RTLD_DEFAULT, "objc_setAssociatedObject"));
2144 $objc_getAssociatedObject = reinterpret_cast<id (*)(id, void *)>(dlsym(RTLD_DEFAULT, "objc_getAssociatedObject"));
2145 $objc_removeAssociatedObjects = reinterpret_cast<void (*)(id)>(dlsym(RTLD_DEFAULT, "objc_removeAssociatedObjects"));
2147 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2149 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
2150 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
2152 Manager_ = [[NSFileManager defaultManager] retain];
2153 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
2155 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
2157 // Load Settings.plist {{{
2158 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
2159 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
2160 SummerBoard_ = [value boolValue];
2162 SummerBoard_ = true;
2164 if (NSNumber *value = [settings objectForKey:@"Debug"])
2165 Debug_ = [value boolValue];
2166 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
2167 UIDebug_ = [value boolValue];
2169 NSArray *themes([settings objectForKey:@"Themes"]);
2171 if (NSString *theme = [settings objectForKey:@"Theme"])
2172 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
2174 [NSNumber numberWithBool:true], @"Active",
2178 for (NSDictionary *theme in themes) {
2179 NSNumber *active([theme objectForKey:@"Active"]);
2180 if (![active boolValue])
2183 NSString *name([theme objectForKey:@"Name"]);
2187 NSString *theme(nil);
2189 #define testForTheme(format...) \
2190 if (theme == nil) { \
2191 NSString *path = [NSString stringWithFormat:format]; \
2192 if ([Manager_ fileExistsAtPath:path]) { \
2193 [Themes_ addObject:path]; \
2198 testForTheme(@"/Library/Themes/%@.theme", name)
2199 testForTheme(@"/Library/Themes/%@", name)
2200 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
2205 // Merge Info.plist {{{
2206 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2208 for (NSString *theme in Themes_)
2209 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
2210 for (NSString *key in [info allKeys])
2211 if ([Info_ objectForKey:key] == nil)
2212 [Info_ setObject:[info objectForKey:key] forKey:key];
2216 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
2217 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
2218 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
2221 // GraphicsServices {{{
2223 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
2227 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
2228 void *(*CGImageReadCreateWithFile)(NSString *, int);
2229 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
2230 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
2232 if (CGImageReadCreateWithFile == NULL) {
2233 void *(*CGImageSourceCreateWithFile)(NSString *, NSDictionary *);
2234 msset(CGImageSourceCreateWithFile, image, "_CGImageSourceCreateWithFile");
2235 MSHookFunction(CGImageSourceCreateWithFile, MSHake(CGImageSourceCreateWithFile));
2237 void *(*CGImageSourceCreateWithURL)(NSURL *, NSDictionary *);
2238 msset(CGImageSourceCreateWithURL, image, "_CGImageSourceCreateWithURL");
2239 MSHookFunction(CGImageSourceCreateWithURL, MSHake(CGImageSourceCreateWithURL));
2245 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
2246 Papered_ = $getTheme$(Wallpapers_) != nil;
2247 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
2249 CFNotificationCenterAddObserver(
2250 CFNotificationCenterGetDarwinNotifyCenter(),
2251 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
2254 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
2255 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
2256 if (MediaPlayer != nil)
2259 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
2260 $MPVideoView = objc_getClass("MPVideoView");
2267 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
2268 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
2269 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v28@0:4{CGRect={CGSize=ff}{CGSize=ff}}8@24");
2270 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
2273 memset(nl, 0, sizeof(nl));
2274 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
2275 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
2276 nl[2].n_un.n_name = (char *) "__UIKitBundle";
2277 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
2278 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
2281 nlset(_UIApplicationImageWithName, nl, 0);
2282 nlset(_UIImageWithNameInDomain, nl, 1);
2283 nlset(_UIKitBundle, nl, 2);
2284 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
2285 nlset(_UISharedImageNameGetIdentifier, nl, 4);
2287 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
2288 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
2289 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
2293 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
2294 NSError *error(nil);
2295 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
2296 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
2298 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);