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(UIImageTableArtwork)
127 MSClassHook(UINavigationBar)
128 MSClassHook(UISharedArtwork)
129 MSClassHook(UIToolbar)
130 MSClassHook(UIStatusBarTimeItemView)
131 MSClassHook(UIWebDocumentView)
133 MSClassHook(CKBalloonView)
134 MSClassHook(CKMessageCell)
135 MSClassHook(CKTimestampView)
136 MSClassHook(CKTranscriptCell)
137 MSClassHook(CKTranscriptController)
138 MSClassHook(CKTranscriptHeaderView)
139 MSClassHook(CKTranscriptTableView)
141 MSClassHook(SBApplication)
142 MSClassHook(SBApplicationIcon)
143 MSClassHook(SBAwayView)
144 MSClassHook(SBBookmarkIcon)
145 MSClassHook(SBButtonBar)
146 MSClassHook(SBCalendarApplicationIcon)
147 MSClassHook(SBCalendarIconContentsView)
148 MSClassHook(SBDockIconListView)
150 MSClassHook(SBIconAccessoryImage)
151 MSMetaClassHook(SBIconAccessoryImage)
152 MSClassHook(SBIconBadge)
153 MSClassHook(SBIconBadgeFactory)
154 MSClassHook(SBIconBadgeImage)
155 MSClassHook(SBIconContentView)
156 MSClassHook(SBIconController)
157 MSClassHook(SBIconLabel)
158 MSClassHook(SBIconLabelImage)
159 MSMetaClassHook(SBIconLabelImage)
160 MSClassHook(SBIconLabelImageParameters)
161 MSClassHook(SBIconList)
162 MSClassHook(SBIconModel)
163 MSClassHook(SBIconView)
164 MSMetaClassHook(SBIconView)
165 //MSClassHook(SBImageCache)
166 MSClassHook(SBSearchView)
167 MSClassHook(SBSearchTableViewCell)
168 MSClassHook(SBSlidingAlertDisplay)
169 MSClassHook(SBStatusBarContentsView)
170 MSClassHook(SBStatusBarController)
171 MSClassHook(SBStatusBarOperatorNameView)
172 MSClassHook(SBStatusBarTimeView)
173 MSClassHook(SBUIController)
174 MSClassHook(SBWallpaperView)
175 MSClassHook(SBWidgetApplicationIcon)
177 extern "C" void WKSetCurrentGraphicsContext(CGContextRef);
179 static struct MSFixClass { MSFixClass() {
180 $UIWebDocumentView = objc_getClass("UIWebBrowserView") ?: $UIWebDocumentView;
181 $SBIcon = objc_getClass("SBIconView") ?: $SBIcon;
183 if ($SBIconList == nil)
184 $SBIconList = objc_getClass("SBIconListView");
185 if ($CKTranscriptController == nil)
186 $CKTranscriptController = objc_getClass("mSMSMessageTranscriptController");
190 static bool Four_($SBDockIconListView != nil);
192 @interface NSObject (wb$SBIconAccessoryImage)
193 + (Class) _imageClassForIcon:(SBIcon *)icon location:(int)location;
196 @interface NSDictionary (WinterBoard)
197 - (UIColor *) wb$colorForKey:(NSString *)key;
198 - (BOOL) wb$boolForKey:(NSString *)key;
201 @implementation NSDictionary (WinterBoard)
203 - (UIColor *) wb$colorForKey:(NSString *)key {
204 NSString *value = [self objectForKey:key];
211 - (BOOL) wb$boolForKey:(NSString *)key {
212 if (NSString *value = [self objectForKey:key])
213 return [value boolValue];
219 static BOOL (*_GSFontGetUseLegacyFontMetrics)();
220 #define $GSFontGetUseLegacyFontMetrics() \
221 (_GSFontGetUseLegacyFontMetrics == NULL ? YES : _GSFontGetUseLegacyFontMetrics())
223 static bool Debug_ = false;
224 static bool UIDebug_ = false;
225 static bool Engineer_ = false;
226 static bool SummerBoard_ = false;
227 static bool SpringBoard_;
229 static UIImage *(*_UIApplicationImageWithName)(NSString *name);
230 static UIImage *(*_UIImageWithNameInDomain)(NSString *name, NSString *domain);
231 static NSBundle *(*_UIKitBundle)();
232 static bool (*_UIPackedImageTableGetIdentifierForName)(NSString *, int *);
233 static int (*_UISharedImageNameGetIdentifier)(NSString *);
235 static NSMutableDictionary *UIImages_ = [[NSMutableDictionary alloc] initWithCapacity:32];
236 static NSMutableDictionary *PathImages_ = [[NSMutableDictionary alloc] initWithCapacity:16];
237 static NSMutableDictionary *Cache_ = [[NSMutableDictionary alloc] initWithCapacity:64];
238 static NSMutableDictionary *Strings_ = [[NSMutableDictionary alloc] initWithCapacity:0];
239 static NSMutableDictionary *Bundles_ = [[NSMutableDictionary alloc] initWithCapacity:2];
241 static NSFileManager *Manager_;
242 static NSMutableArray *Themes_;
244 static NSDictionary *English_;
245 static NSMutableDictionary *Info_;
248 static NSMutableDictionary *Themed_ = [[NSMutableDictionary alloc] initWithCapacity:128];
250 static unsigned Scale_ = 0;
252 static unsigned $getScale$(NSString *path) {
253 NSString *name(path);
255 #define StripName(strip) \
256 if ([name hasSuffix:@ strip]) \
257 name = [name substringWithRange:NSMakeRange(0, [name length] - sizeof(strip) - 1)];
261 StripName("~iphone");
264 return [name hasSuffix:@"@2x"] ? 2 : 1;
267 static NSArray *$useScale$(NSArray *files, bool use = true) {
268 if (use && Scale_ == 0) {
269 UIScreen *screen([UIScreen mainScreen]);
270 if ([screen respondsToSelector:@selector(scale)])
271 Scale_ = [screen scale];
279 NSString *idiom(IsWild_ ? @"ipad" : @"iphone");
281 NSMutableArray *scaled([NSMutableArray arrayWithCapacity:([files count] * 4)]);
283 for (NSString *file in files) {
284 NSString *base([file stringByDeletingPathExtension]);
285 NSString *extension([file pathExtension]);
289 [scaled addObject:[NSString stringWithFormat:@"%@@2x~%@.%@", base, idiom, extension]];
290 [scaled addObject:[NSString stringWithFormat:@"%@@2x.%@", base, extension]];
293 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
295 // if (!IsWild_) <- support old themes
296 [scaled addObject:file];
297 } else if ([base hasSuffix: @"@2x"]) {
298 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
299 [scaled addObject:file];
301 // XXX: this actually can't be used, as the person loading the file doesn't realize that the @2x changed
302 /*NSString *rest([base substringWithRange:NSMakeRange(0, [base length] - 3)]);
303 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", rest, idiom, extension]];
304 [scaled addObject:[rest stringByAppendingPathExtension:extension]];*/
306 // XXX: this code isn't really complete
308 [scaled addObject:file];
310 if ([base hasSuffix:[NSString stringWithFormat:@"~%@", idiom]])
311 [scaled addObject:[[base substringWithRange:NSMakeRange(0, [base length] - 1 - [idiom length])] stringByAppendingPathExtension:extension]];
318 static NSString *$getTheme$(NSArray *files, NSArray *themes = Themes_) {
319 // XXX: this is not reasonable; OMG
322 @synchronized (Themed_) {
323 if (NSString *path = [Themed_ objectForKey:key])
324 return reinterpret_cast<id>(path) == [NSNull null] ? nil : path;
328 NSLog(@"WB:Debug: %@", [files description]);
332 for (NSString *theme in Themes_)
333 for (NSString *file in files) {
334 path = [NSString stringWithFormat:@"%@/%@", theme, file];
335 if ([Manager_ fileExistsAtPath:path]) {
336 if ([[Manager_ pathContentOfSymbolicLinkAtPath:path] isEqualToString:@"/"])
345 @synchronized (Themed_) {
346 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:key];
352 // $pathForFile$inBundle$() {{{
353 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool ui) {
354 NSString *identifier = [bundle bundleIdentifier];
355 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
357 if (identifier != nil)
358 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
359 if (NSString *folder = [[bundle bundlePath] lastPathComponent]) {
360 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
361 NSString *base([folder stringByDeletingPathExtension]);
362 if ([base hasSuffix:@"~iphone"])
363 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 7)], [folder pathExtension], file]];
364 if ([base hasSuffix:@"~ipad"])
365 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 5)], [folder pathExtension], file]];
368 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
370 #define remapResourceName(oldname, newname) \
371 else if ([file isEqualToString:(oldname)]) \
372 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
374 bool summer(SpringBoard_ && SummerBoard_);
376 if (identifier == nil);
377 else if ([identifier isEqualToString:@"com.apple.chatkit"])
378 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
379 else if ([identifier isEqualToString:@"com.apple.calculator"])
380 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
381 else if ([identifier isEqualToString:@"com.apple.Maps"] && [file isEqualToString:@"Icon-57@2x.png"])
382 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.Maps/icon.png"]];
384 remapResourceName(@"FSO_BG.png", @"StatusBar")
385 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
386 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
388 [names addObject:[NSString stringWithFormat:@"Fallback/%@", file]];
390 if (NSString *path = $getTheme$($useScale$(names, ui)))
397 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
398 NSString *identifier = [self bundleIdentifier];
399 NSString *path = [self path];
400 NSString *folder = [path lastPathComponent];
401 NSString *dname = [self displayName];
402 NSString *didentifier = [self displayIdentifier];
405 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
407 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
409 /* XXX: I might need to keep this for backwards compatibility
410 if (identifier != nil)
411 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
413 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
415 #define testForIcon(Name) \
416 if (NSString *name = Name) \
417 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
419 if (![didentifier isEqualToString:identifier])
420 testForIcon(didentifier);
422 testForIcon(identifier);
425 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
428 if (didentifier != nil) {
429 testForIcon([English_ objectForKey:didentifier]);
431 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
432 if ([parts count] != 1)
433 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
434 testForIcon([english objectForKey:[parts lastObject]]);
437 if (NSString *path = $getTheme$(names))
443 // -[NSBundle wb$bundleWithFile] {{{
444 @interface NSBundle (WinterBoard)
445 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
448 @implementation NSBundle (WinterBoard)
450 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
451 path = [path stringByDeletingLastPathComponent];
452 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
455 NSBundle *bundle([Bundles_ objectForKey:path]);
456 if (reinterpret_cast<id>(bundle) == [NSNull null])
458 else if (bundle == nil) {
459 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
460 bundle = [NSBundle bundleWithPath:path];
462 bundle = [NSBundle wb$bundleWithFile:path];
464 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
465 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
473 // -[NSString wb$themedPath] {{{
474 @interface NSString (WinterBoard)
475 - (NSString *) wb$themedPath;
478 @implementation NSString (WinterBoard)
480 - (NSString *) wb$themedPath {
481 if ([self hasPrefix:@"/Library/Themes/"])
485 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
487 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
488 NSString *file([self stringByResolvingSymlinksInPath]);
489 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
490 if ([file hasPrefix:prefix]) {
491 NSUInteger length([prefix length]);
492 if (length != [file length])
493 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
504 void WBLogRect(const char *tag, struct CGRect rect) {
505 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
508 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
509 CGRect frame([view frame]);
510 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]);
512 for (UIView *child in [view subviews])
513 WBLogHierarchy(child, index++, indent + 1);
516 UIImage *$cacheForImage$(UIImage *image) {
517 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
518 CGRect rect = {CGPointMake(1, 1), [image size]};
519 CGSize size = {rect.size.width + 2, rect.size.height + 2};
521 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
522 CGColorSpaceRelease(space);
524 CGContextDrawImage(context, rect, [image CGImage]);
525 CGImageRef ref(CGBitmapContextCreateImage(context));
526 CGContextRelease(context);
528 UIImage *cache([UIImage imageWithCGImage:ref]);
534 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
535 //if ([name isEqualToString:@"icons"]) return nil;
536 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
539 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
540 NSString *key([icon displayIdentifier]);
542 if (UIImage *image = [icon icon]) {
543 CGSize size = [image size];
544 if (size.width != 59 || size.height != 60) {
545 UIImage *cache($cacheForImage$(image));
546 [Cache_ setObject:cache forKey:key];
551 _SBIconModel$cacheImageForIcon$(self, sel, icon);
554 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
555 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
556 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
558 NSString *key([icon displayIdentifier]);
560 if (UIImage *image = [icon icon]) {
561 CGSize size = [image size];
562 if (size.width != 59 || size.height != 60) {
563 UIImage *cache($cacheForImage$(image));
564 [Cache_ setObject:cache forKey:key];
570 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
571 NSString *key([icon displayIdentifier]);
572 if (UIImage *image = [Cache_ objectForKey:key])
575 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
578 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
580 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
581 NSString *key([icon displayIdentifier]);
582 if (UIImage *image = [Cache_ objectForKey:key])
585 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
588 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
589 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
590 [self setBackgroundColor:[UIColor clearColor]];
591 for (UIView *child in [self subviews])
592 [child setBackgroundColor:[UIColor clearColor]];
596 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
597 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
598 [self setBackgroundColor:[UIColor clearColor]];
602 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
603 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
604 float inset([self edgeInset]);
605 [[UIColor clearColor] set];
606 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
607 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
610 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
611 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
612 if (NSString *path = $pathForIcon$([self application]))
613 return [UIImage imageWithContentsOfFile:path];
614 return _SBApplicationIcon$icon(self, sel);
617 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
619 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
620 if (IsWild_ && false) // XXX: delete this code, it should not be supported
621 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
622 return [UIImage imageWithContentsOfFile:path72];
623 if (NSString *path = $pathForIcon$([self application]))
624 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
626 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
627 width = [$SBIcon defaultIconImageSize].width;
630 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
633 return _SBApplicationIcon$generateIconImage$(self, sel, type);
636 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
638 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
639 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
640 return [UIImage imageWithContentsOfFile:path];
641 return _SBWidgetApplicationIcon$icon(self, sel);
644 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
646 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
647 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
648 return [UIImage imageWithContentsOfFile:path];
649 return _SBBookmarkIcon$icon(self, sel);
652 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
653 if (NSString *path = $pathForIcon$(self))
655 return _SBApplication$pathForIcon(self, sel);
658 static UIImage *CachedImageAtPath(NSString *path) {
659 path = [path stringByResolvingSymlinksInPath];
660 UIImage *image = [PathImages_ objectForKey:path];
662 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
663 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
665 image = [image autorelease];
666 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
670 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
671 NSBundle *bundle = [NSBundle mainBundle];
673 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
674 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
675 return CachedImageAtPath(path);
676 return __UIApplicationImageWithName(name);
679 #define WBDelegate(delegate) \
680 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
682 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
683 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
685 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
689 - (void) forwardInvocation:(NSInvocation*)inv { \
690 SEL sel = [inv selector]; \
691 if ([delegate respondsToSelector:sel]) \
692 [inv invokeWithTarget:delegate]; \
694 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
697 // %hook -[NSBundle pathForResource:ofType:] {{{
698 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
699 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
701 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
702 if (NSString *path = $pathForFile$inBundle$(file, self, false))
704 return MSOldCall(resource, type);
708 static void $drawLabel$(NSString *label, CGRect rect, NSString *style, NSString *custom) {
709 bool ellipsis(false);
710 float max = rect.size.width - 11, width;
712 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
715 size_t length([label length]);
716 float spacing((width - max) / (length - 1));
718 if (spacing > 1.25) {
720 label = [label substringToIndex:(length - 1)];
724 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
728 label = [label stringByAppendingString:@"..."];
731 style = [style stringByAppendingString:custom];
733 CGSize size = [label sizeWithStyle:style forWidth:rect.size.width];
734 [label drawAtPoint:CGPointMake((rect.size.width - size.width) / 2 + rect.origin.x, rect.origin.y) withStyle:style];
737 static struct WBStringDrawingState {
738 WBStringDrawingState *next_;
742 } *stringDrawingState_;
744 extern "C" CGColorSpaceRef CGContextGetFillColorSpace(CGContextRef);
745 extern "C" void CGContextGetFillColor(CGContextRef, CGFloat[]);
747 static NSString *WBColorMarkup() {
748 CGContextRef context(UIGraphicsGetCurrentContext());
749 //NSLog(@"XXX:1:%p", context);
753 CGColorSpaceRef space(CGContextGetFillColorSpace(context));
754 //NSLog(@"XXX:2:%p", space);
758 size_t number(CGColorSpaceGetNumberOfComponents(space));
759 //NSLog(@"XXX:3:%u", number);
763 CGFloat components[number + 1];
764 CGContextGetFillColor(context, components);
787 return [NSString stringWithFormat:@"color: rgba(%g, %g, %g, %g)", r * 255, g * 255, b * 255, a];
790 MSInstanceMessageHook6(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode,letterSpacing,includeEmoji, CGPoint, point, float, width, UIFont *, font, UILineBreakMode, mode, float, spacing, BOOL, emoji) {
791 //NSLog(@"XXX: @\"%@\" %g", self, spacing);
793 WBStringDrawingState *state(stringDrawingState_);
795 return MSOldCall(point, width, font, mode, spacing, emoji);
797 if (--state->count_ == 0)
798 stringDrawingState_ = state->next_;
799 if (state->info_ == nil)
800 return MSOldCall(point, width, font, mode, spacing, emoji);
802 NSString *info([Info_ objectForKey:state->info_]);
804 return MSOldCall(point, width, font, mode, spacing, emoji);
806 NSString *base(state->base_ ?: @"");
807 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
808 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
812 extern "C" NSString *NSStringFromCGRect(CGRect rect);
814 MSInstanceMessageHook7(CGSize, NSString, _drawInRect,withFont,lineBreakMode,alignment,lineSpacing,includeEmoji,truncationRect, CGRect, rect, UIFont *, font, UILineBreakMode, mode, UITextAlignment, alignment, float, spacing, BOOL, emoji, CGRect, truncation) {
815 //NSLog(@"XXX: &\"%@\" %@ \"%@\" %u %u %g %u %@", self, NSStringFromCGRect(rect), font, mode, alignment, spacing, emoji, NSStringFromCGRect(truncation));
817 WBStringDrawingState *state(stringDrawingState_);
819 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
821 if (--state->count_ == 0)
822 stringDrawingState_ = state->next_;
823 if (state->info_ == nil)
824 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
826 NSString *info([Info_ objectForKey:state->info_]);
828 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
833 case UITextAlignmentLeft:
836 case UITextAlignmentCenter:
837 textAlign = @"center";
839 case UITextAlignmentRight:
840 textAlign = @"right";
844 NSString *base(state->base_ ?: @"");
845 NSString *extra([NSString stringWithFormat:@"text-align: %@", textAlign]);
848 $drawLabel$(self, rect, [NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], WBColorMarkup(), base], info);
850 [self drawInRect:rect withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
855 MSInstanceMessageHook4(CGSize, NSString, sizeWithFont,forWidth,lineBreakMode,letterSpacing, UIFont *, font, float, width, UILineBreakMode, mode, float, spacing) {
856 //NSLog(@"XXX: #\"%@\" \"%@\" %g %u %g", self, font, width, mode, spacing);
858 WBStringDrawingState *state(stringDrawingState_);
860 return MSOldCall(font, width, mode, spacing);
862 if (--state->count_ == 0)
863 stringDrawingState_ = state->next_;
864 if (state->info_ == nil)
865 return MSOldCall(font, width, mode, spacing);
867 NSString *info([Info_ objectForKey:state->info_]);
869 return MSOldCall(font, width, mode, spacing);
871 NSString *base(state->base_ ?: @"");
872 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
873 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info] forWidth:width];
876 MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) {
877 //NSLog(@"XXX: ?\"%@\"", self);
879 WBStringDrawingState *state(stringDrawingState_);
881 return MSOldCall(font);
883 if (--state->count_ == 0)
884 stringDrawingState_ = state->next_;
885 if (state->info_ == nil)
886 return MSOldCall(font);
888 NSString *info([Info_ objectForKey:state->info_]);
890 return MSOldCall(font);
892 NSString *base(state->base_ ?: @"");
893 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), base, info] forWidth:65535];
896 MSClassMessageHook2(UIImage *, SBIconAccessoryImage, checkoutAccessoryImageForIcon,location, id, icon, int, location) {
897 if ([self _imageClassForIcon:icon location:location] != $SBIconBadgeImage)
898 return MSOldCall(icon, location);
900 WBStringDrawingState badgeState = {NULL, -1, @""
903 stringDrawingState_ = &badgeState;
905 UIImage *image(MSOldCall(icon, location));
907 stringDrawingState_ = NULL;
911 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
912 WBStringDrawingState badgeState = {NULL, -1, @""
915 stringDrawingState_ = &badgeState;
917 UIImage *image(MSOldCall(text));
919 stringDrawingState_ = NULL;
923 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
924 WBStringDrawingState dayState = {NULL, 2, @""
925 // XXX: this is only correct on an iPod dock
926 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
927 , @"CalendarIconDayStyle"};
929 WBStringDrawingState sizeState = {&dayState, 7, nil, nil};
931 WBStringDrawingState dateState = {&sizeState, 2, @""
932 , @"CalendarIconDateStyle"};
934 stringDrawingState_ = &dateState;
936 UIImage *image(MSOldCall(type));
938 stringDrawingState_ = NULL;
942 MSInstanceMessageHook1(UIImage *, UIStatusBarTimeItemView, contentsImageForStyle, int, style) {
943 WBStringDrawingState timeState = {NULL, 0, @""
946 stringDrawingState_ = &timeState;
948 UIImage *image(MSOldCall(style));
950 stringDrawingState_ = NULL;
954 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
955 NSBundle *bundle([NSBundle mainBundle]);
957 CFLocaleRef locale(CFLocaleCopyCurrent());
958 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
961 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
963 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
964 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
965 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
966 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
970 CFRelease(formatter);
972 NSString *datestyle([@""
973 "font-family: Helvetica; "
974 "font-weight: bold; "
977 "" stringByAppendingString:(IsWild_
978 ? @"font-size: 54px; "
979 : @"font-size: 39px; "
982 NSString *daystyle([@""
983 "font-family: Helvetica; "
984 "font-weight: bold; "
986 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
987 "" stringByAppendingString:(IsWild_
988 ? @"font-size: 11px; "
989 : @"font-size: 9px; "
992 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
993 datestyle = [datestyle stringByAppendingString:style];
994 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
995 daystyle = [daystyle stringByAppendingString:style];
997 float width([self bounds].size.width);
999 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
1000 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
1002 unsigned base0(IsWild_ ? 89 : 70);
1003 if ($GSFontGetUseLegacyFontMetrics())
1005 unsigned base1(IsWild_ ? 18 : 16);
1012 [(NSString *)date drawAtPoint:CGPointMake(
1013 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
1014 ) withStyle:datestyle];
1016 [(NSString *)day drawAtPoint:CGPointMake(
1017 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
1018 ) withStyle:daystyle];
1024 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
1025 void $setBarStyle$_(NSString *name, int &style) {
1027 NSLog(@"WB:Debug:%@Style:%d", name, style);
1028 NSNumber *number = nil;
1030 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
1032 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
1033 if (number != nil) {
1034 style = [number intValue];
1036 NSLog(@"WB:Debug:%@Style=%d", name, style);
1040 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
1041 $setBarStyle$_(@"Toolbar", style);
1042 return MSOldCall(style);
1045 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
1046 $setBarStyle$_(@"NavigationBar", style);
1047 return MSOldCall(style);
1051 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
1052 [[self superview] setBackgroundColor:[UIColor clearColor]];
1053 _SBButtonBar$didMoveToSuperview(self, sel);
1056 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
1057 [[self superview] setBackgroundColor:[UIColor clearColor]];
1058 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
1061 static NSArray *Wallpapers_;
1062 static bool Papered_;
1063 static bool Docked_;
1064 static bool SMSBackgrounded_;
1065 static NSString *WallpaperFile_;
1066 static UIImageView *WallpaperImage_;
1067 static UIWebDocumentView *WallpaperPage_;
1068 static NSURL *WallpaperURL_;
1070 #define _release(object) \
1071 do if (object != nil) { \
1076 static UIImage *$getImage$(NSString *path) {
1077 UIImage *image([UIImage imageWithContentsOfFile:path]);
1079 unsigned scale($getScale$(path));
1080 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
1081 [image setScale:scale];
1086 static UIImage *$getDefaultDesktopImage$() {
1087 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
1088 return $getImage$(path);
1092 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
1093 return $getDefaultDesktopImage$() ?: MSOldCall();
1096 MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
1097 return $getDefaultDesktopImage$() ?: MSOldCall();
1100 MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
1101 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
1102 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
1103 if (UIImage *image = $getDefaultDesktopImage$()) {
1104 [self setImage:image];
1114 // %hook -[SBUIController init] {{{
1115 MSInstanceMessageHook0(id, SBUIController, init) {
1120 NSString *paper($getTheme$(Wallpapers_));
1122 paper = [paper stringByDeletingLastPathComponent];
1126 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
1127 char *machine = new char[size];
1129 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
1130 perror("sysctlbyname(\"hw.machine\", ?)");
1135 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
1139 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
1142 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
1143 if (&_wallpaperView != NULL) {
1144 [_wallpaperView removeFromSuperview];
1145 [_wallpaperView release];
1146 _wallpaperView = nil;
1150 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
1151 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
1154 if (&_contentLayer != NULL)
1155 player = &_contentLayer;
1156 else if (&_contentView != NULL)
1157 player = &_contentView;
1160 UIView *layer(player == NULL ? nil : *player);
1162 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
1163 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
1164 [window setContentView:content];
1166 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
1167 [window setBackgroundColor:[_window backgroundColor]];
1168 [_window setBackgroundColor:[UIColor clearColor]];
1170 [window setLevel:-1000];
1171 [window setHidden:NO];
1173 /*if (player != NULL)
1174 *player = content;*/
1176 [content setBackgroundColor:[layer backgroundColor]];
1177 [layer setBackgroundColor:[UIColor clearColor]];
1180 if (!SummerBoard_ || !IsWild_)
1183 CGRect bounds([content bounds]);
1184 bounds.origin.y = -30;
1185 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
1186 [content addSubview:indirect];
1187 [indirect zoomToScale:2.4];
1190 _release(WallpaperFile_);
1191 _release(WallpaperImage_);
1192 _release(WallpaperPage_);
1193 _release(WallpaperURL_);
1196 NSArray *themes([NSArray arrayWithObject:paper]);
1198 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1202 static AVController *controller_(nil);
1203 if (controller_ == nil) {
1204 AVQueue *queue([AVQueue avQueue]);
1205 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1208 AVQueue *queue([controller_ queue]);
1210 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1211 [controller_ setLayer:[video _layer]];
1213 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1214 [queue appendItem:item error:&error];
1216 [controller_ play:&error];
1217 #elif UseMPMoviePlayerController
1218 NSURL *url([NSURL fileURLWithPath:path]);
1219 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1220 controller.movieControlMode = MPMovieControlModeHidden;
1223 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1224 [video setMovieWithPath:path];
1225 [video setRepeatMode:1];
1226 [video setRepeatGap:-1];
1227 [video playFromBeginning];;
1230 [indirect addSubview:video];
1233 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1234 if (UIImage *image = $getImage$(path)) {
1235 WallpaperFile_ = [path retain];
1236 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1237 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1238 [WallpaperImage_ setAlpha:[number floatValue]];
1239 [indirect addSubview:WallpaperImage_];
1243 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1244 CGRect bounds = [indirect bounds];
1246 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1247 [view setAutoresizes:true];
1249 WallpaperPage_ = [view retain];
1250 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1252 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1254 [view setBackgroundColor:[UIColor clearColor]];
1255 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1256 [view setDrawsBackground:NO];
1257 [[view webView] setDrawsBackground:NO];
1259 [indirect addSubview:view];
1263 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1264 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1265 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1266 if ([Manager_ fileExistsAtPath:html]) {
1267 CGRect bounds = [indirect bounds];
1269 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1270 [view setAutoresizes:true];
1272 NSURL *url = [NSURL fileURLWithPath:html];
1273 [view loadRequest:[NSURLRequest requestWithURL:url]];
1275 [view setBackgroundColor:[UIColor clearColor]];
1276 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1277 [view setDrawsBackground:NO];
1278 [[view webView] setDrawsBackground:NO];
1280 [indirect addSubview:view];
1288 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1289 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1290 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1292 if (path != nil && _backgroundView != nil)
1295 _SBAwayView$updateDesktopImage$(self, sel, image);
1298 CGRect bounds = [self bounds];
1300 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1301 [view setAutoresizes:true];
1303 if (WallpaperPage_ != nil)
1304 [WallpaperPage_ release];
1305 WallpaperPage_ = [view retain];
1307 if (WallpaperURL_ != nil)
1308 [WallpaperURL_ release];
1309 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1311 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1313 [[view webView] setDrawsBackground:false];
1314 [view setBackgroundColor:[UIColor clearColor]];
1316 [self insertSubview:view aboveSubview:_backgroundView];
1320 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1321 extern "C" CGColorRef CGGStateGetFillColor(void *);
1322 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1323 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1325 /* WBTimeLabel {{{ */
1326 @interface WBTimeLabel : NSProxy {
1328 _transient SBStatusBarTimeView *view_;
1331 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1335 @implementation WBTimeLabel
1342 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1343 time_ = [time retain];
1348 - (NSString *) description {
1354 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1355 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1356 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1358 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1359 "font-family: Helvetica; "
1360 "font-weight: bold; "
1363 "%@", _mode ? @"white" : @"black", custom]];
1368 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1373 /* WBBadgeLabel {{{ */
1374 @interface WBBadgeLabel : NSProxy {
1378 - (id) initWithBadge:(NSString *)badge;
1379 - (NSString *) description;
1383 @implementation WBBadgeLabel
1390 - (id) initWithBadge:(NSString *)badge {
1391 badge_ = [badge retain];
1395 - (NSString *) description {
1396 return [badge_ description];
1401 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1402 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1403 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1404 "font-family: Helvetica; "
1405 "font-weight: bold; "
1413 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1420 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1421 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1422 alpha = [number floatValue];
1423 return MSOldCall(alpha);
1426 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1427 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1428 alpha = [number floatValue];
1429 return MSOldCall(alpha);
1432 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1433 if ((self = MSOldCall()) != nil) {
1434 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1435 // XXX: note: this is overridden above, which is silly
1436 float alpha([number floatValue]);
1437 if ([self respondsToSelector:@selector(setIconImageAlpha:)])
1438 [self setIconImageAlpha:alpha];
1439 if ([self respondsToSelector:@selector(setIconLabelAlpha:)])
1440 [self setIconLabelAlpha:alpha];
1441 if ([self respondsToSelector:@selector(setAlpha:)])
1442 [self setAlpha:alpha];
1447 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1448 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1449 alpha = [number floatValue];
1450 return MSOldCall(alpha);
1454 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1455 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1456 id &_badge(MSHookIvar<id>(self, "_badge"));
1458 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1463 void SBStatusBarController$setStatusBarMode(int &mode) {
1465 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1466 if (mode < 100) // 104:hidden 105:glowing
1467 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1468 mode = [number intValue];
1471 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1472 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1473 SBStatusBarController$setStatusBarMode(mode);
1474 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1477 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1478 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1479 SBStatusBarController$setStatusBarMode(mode);
1480 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1483 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) {
1484 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1485 SBStatusBarController$setStatusBarMode(mode);
1486 //NSLog(@"mode=%u", mode);
1487 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1490 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1491 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1492 mode = [number intValue];
1493 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1496 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1497 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1499 NSLog(@"operatorNameStyle= %@", style);
1500 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1501 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1505 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1507 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1508 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1511 // XXX: replace this with [SBStatusBarTimeView tile]
1512 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1513 id &_time(MSHookIvar<id>(self, "_time"));
1514 if (_time != nil && [_time class] != [WBTimeLabel class])
1515 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1516 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1519 @interface UIView (WinterBoard)
1520 - (bool) wb$isWBImageView;
1521 - (void) wb$logHierarchy;
1522 - (void) wb$setBackgroundColor:(UIColor *)color;
1525 @implementation UIView (WinterBoard)
1527 - (bool) wb$isWBImageView {
1531 - (void) wb$logHierarchy {
1532 WBLogHierarchy(self);
1535 - (void) wb$setBackgroundColor:(UIColor *)color {
1536 [self setBackgroundColor:color];
1537 for (UIView *child in [self subviews])
1538 [child wb$setBackgroundColor:color];
1543 @interface WBImageView : UIImageView {
1546 - (bool) wb$isWBImageView;
1547 - (void) wb$updateFrame;
1550 @implementation WBImageView
1552 - (bool) wb$isWBImageView {
1556 - (void) wb$updateFrame {
1557 CGRect frame([self frame]);
1560 for (UIView *view(self); ; ) {
1561 view = [view superview];
1564 frame.origin.y -= [view frame].origin.y;
1567 [self setFrame:frame];
1572 static void SBIconList$updateFrames$(SBIconList *self) {
1573 NSArray *subviews([self subviews]);
1574 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1575 if (view != nil && [view wb$isWBImageView])
1576 [view wb$updateFrame];
1579 MSHook(void, SBIconList$didMoveToSuperview, SBIconList *self, SEL sel) {
1580 SBIconList$updateFrames$(self);
1581 _SBIconList$didMoveToSuperview(self, sel);
1584 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1585 SBIconList$updateFrames$(self);
1586 _SBIconList$setFrame$(self, sel, frame);
1589 static void $addPerPageView$(unsigned i, UIView *list) {
1590 NSString *path($getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]]));
1594 NSArray *subviews([list subviews]);
1596 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1597 if (view == nil || ![view wb$isWBImageView]) {
1598 view = [[[WBImageView alloc] init] autorelease];
1599 [list insertSubview:view atIndex:0];
1602 UIImage *image([UIImage imageWithContentsOfFile:path]);
1604 CGRect frame([view frame]);
1605 frame.size = [image size];
1606 [view setFrame:frame];
1608 [view setImage:image];
1609 [view wb$updateFrame];
1612 static void $addPerPageViews$(NSArray *lists) {
1613 for (unsigned i(0), e([lists count]); i != e; ++i)
1614 $addPerPageView$(i, [lists objectAtIndex:i]);
1617 MSInstanceMessageHook0(void, SBIconController, updateNumberOfRootIconLists) {
1618 NSArray *&_rootIconLists(MSHookIvar<NSArray *>(self, "_rootIconLists"));
1619 $addPerPageViews$(_rootIconLists);
1623 MSInstanceMessageHook0(void, SBIconContentView, layoutSubviews) {
1626 if (SBIconController *controller = [$SBIconController sharedInstance]) {
1627 UIView *&_dockContainerView(MSHookIvar<UIView *>(controller, "_dockContainerView"));
1628 if (&_dockContainerView != NULL)
1629 [[_dockContainerView superview] bringSubviewToFront:_dockContainerView];
1633 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1634 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1635 $addPerPageViews$([_iconModel iconLists]);
1636 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1639 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1640 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1642 [self setClipsToBounds:NO];
1646 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1647 static bool gssc(false);
1649 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1650 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1653 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1654 [Info_ setObject:[NSNumber numberWithBool:(
1656 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1657 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1658 )] forKey:@"UndockedIconLabels"];
1661 id &_label(MSHookIvar<id>(self, "_label"));
1662 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1665 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1666 [_label setInDock:docked];
1668 _SBIconLabel$setInDock$(self, sel, docked);
1669 [self setNeedsDisplay];
1672 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1673 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1676 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1677 _SBDockIconListView$setFrame$(self, sel, frame);
1680 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1681 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1682 NSString *identifier = [self bundleIdentifier];
1683 NSLocale *locale = [NSLocale currentLocale];
1684 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1686 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1687 NSString *file = table == nil ? @"Localizable" : table;
1688 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1689 NSDictionary *strings;
1690 if ((strings = [Strings_ objectForKey:name]) != nil) {
1691 if (static_cast<id>(strings) != [NSNull null]) strings:
1692 if (NSString *value = [strings objectForKey:key])
1694 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1697 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1698 [Strings_ setObject:[strings autorelease] forKey:name];
1702 [Strings_ setObject:[NSNull null] forKey:name];
1703 return MSOldCall(key, value, table);
1706 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1707 MSClassHook(WebCoreFrameBridge)
1709 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1712 void **core(reinterpret_cast<void **>([node _node]));
1713 if (core == NULL || core[6] == NULL)
1715 return MSOldCall(node, width);
1719 MSInstanceMessage1(void, SBIconLabel, drawRect, CGRect, rect) {
1720 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1723 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1724 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1726 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1728 NSString *style = [NSString stringWithFormat:@""
1729 "font-family: Helvetica; "
1730 "font-weight: bold; "
1732 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1733 ? @"font-size: 12px; "
1734 : @"font-size: 11px; "
1738 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1740 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1742 NSString *custom([Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")]);
1744 $drawLabel$(label, [self bounds], style, custom);
1747 MSInstanceMessage0(CGImageRef, SBIconLabel, buildLabelImage) {
1748 bool docked((MSHookIvar<unsigned>(self, "_inDock") & 0x2) != 0);
1750 WBStringDrawingState labelState = {NULL, 0, @""
1751 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1753 stringDrawingState_ = &labelState;
1756 CGImageRef image(MSOldCall());
1759 stringDrawingState_ = NULL;
1763 static bool wb$inDock(id parameters) {
1764 return [$objc_getAssociatedObject(parameters, @selector(wb$inDock)) boolValue];
1767 MSInstanceMessage0(NSUInteger, SBIconLabelImageParameters, hash) {
1768 return MSOldCall() + (wb$inDock(self) ? 0xdeadbeef : 0xd15ea5e);
1771 MSClassMessage2(id, SBIconView, _labelImageParametersForIcon,location, id, icon, int, location) {
1772 if (id parameters = MSOldCall(icon, location)) {
1773 $objc_setAssociatedObject(parameters, @selector(wb$inDock), [NSNumber numberWithBool:(location == 1)], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1778 MSClassMessage1(UIImage *, SBIconLabelImage, _drawLabelImageForParameters, id, parameters) {
1779 bool docked(wb$inDock(parameters));
1781 WBStringDrawingState labelState = {NULL, 0, @""
1782 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1784 stringDrawingState_ = &labelState;
1787 UIImage *image(MSOldCall(parameters));
1790 stringDrawingState_ = NULL;
1795 MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1796 if ((self = MSOldCall(frame, delegate)) != nil) {
1797 [self setBackgroundColor:[UIColor clearColor]];
1801 MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1802 return SMSBackgrounded_ ? NO : MSOldCall();
1805 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1806 [self wb$setBackgroundColor:[UIColor clearColor]];
1810 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1812 [balloon setBackgroundColor:[UIColor clearColor]];
1815 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1816 MSOldCall([UIColor clearColor]);
1817 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1821 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1822 if ((self = MSOldCall(style, reuse)) != nil) {
1823 [self setBackgroundColor:[UIColor clearColor]];
1824 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1829 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1830 if ((self = MSOldCall(style, reuse)) != nil) {
1831 [self setBackgroundColor:[UIColor clearColor]];
1832 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1836 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1837 if ((self = MSOldCall(style, reuse)) != nil) {
1838 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1839 [_label setBackgroundColor:[UIColor clearColor]];
1843 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1844 MSOldCall(UITableViewCellSeparatorStyleNone);
1847 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1848 if ((self = MSOldCall(frame, style)) != nil) {
1849 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1853 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1856 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1857 if (UIImage *image = $getImage$(path)) {
1858 SMSBackgrounded_ = true;
1860 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1861 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1863 if (&_transcriptTable != NULL)
1864 table = _transcriptTable;
1865 else if (&_transcriptLayer != NULL)
1866 table = _transcriptLayer;
1870 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1871 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1874 [placard insertSubview:background atIndex:0];
1876 [table setBackgroundColor:[UIColor clearColor]];
1877 [placard insertSubview:background belowSubview:table];
1883 MSInstanceMessage2(UISharedArtwork *, UISharedArtwork, initWithName,inBundle, NSString *, name, NSBundle *, bundle) {
1884 if ((self = MSOldCall(name, bundle)) != nil) {
1885 $objc_setAssociatedObject(self, @selector(wb$bundle), bundle, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1889 MSInstanceMessage1(UIImage *, UIImageTableArtwork, imageNamed, NSString *, name) {
1890 NSBundle *bundle($objc_getAssociatedObject(self, @selector(wb$bundle)));
1892 NSLog(@"WB:Debug:[UIImageTableArtwork[%@] imageNamed:\"%@\"]", bundle, name);
1894 return MSOldCall(name);
1895 UIImage *image = [UIImages_ objectForKey:name];
1897 return reinterpret_cast<id>(image) == [NSNull null] ? MSOldCall(name) : image;
1898 if (NSString *path = $pathForFile$inBundle$(name, bundle, true))
1899 image = $getImage$(path);
1900 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:name];
1904 image = MSOldCall(name);
1907 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1908 if (![Manager_ fileExistsAtPath:path])
1909 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1915 // %hook _UIImageWithName() {{{
1916 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1918 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1925 if (_UIPackedImageTableGetIdentifierForName != NULL)
1926 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1927 else if (_UISharedImageNameGetIdentifier != NULL) {
1928 identifier = _UISharedImageNameGetIdentifier(name);
1929 packed = identifier != -1;
1936 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1939 return __UIImageWithName(name);
1941 NSNumber *key([NSNumber numberWithInt:identifier]);
1942 UIImage *image([UIImages_ objectForKey:key]);
1944 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1945 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1946 image = $getImage$(path);
1947 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1951 image = __UIImageWithName(name);
1954 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1955 if (![Manager_ fileExistsAtPath:path])
1956 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1963 // %hook _UIImageWithNameInDomain() {{{
1964 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1965 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1966 UIImage *image([PathImages_ objectForKey:key]);
1968 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1970 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1971 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1972 image = $getImage$(path);
1973 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1974 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1978 // %hook GSFontCreateWithName() {{{
1979 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1981 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1982 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1983 name = [font UTF8String];
1984 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1985 // size *= [scale floatValue];
1986 return _GSFontCreateWithName(name, traits, size);
1990 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1991 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1993 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1995 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1997 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1998 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
2000 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
2003 NSString *path = [NSString stringWithUTF8String:a1];
2004 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
2005 NSString *file = [path substringFromIndex:31];
2006 for (NSString *theme in Themes_) {
2007 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
2008 if ([Manager_ fileExistsAtPath:path]) {
2009 strcpy(a1, [path UTF8String]);
2018 static void ChangeWallpaper(
2019 CFNotificationCenterRef center,
2023 CFDictionaryRef info
2026 NSLog(@"WB:Debug:ChangeWallpaper!");
2029 if (WallpaperFile_ != nil) {
2030 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
2032 image = [image autorelease];
2035 if (WallpaperImage_ != nil)
2036 [WallpaperImage_ setImage:image];
2037 if (WallpaperPage_ != nil)
2038 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
2042 #define WBRename(name, sel, imp) \
2043 MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp, &_ ## name ## $ ## imp)
2045 template <typename Type_>
2046 static void msset(Type_ &function, MSImageRef image, const char *name) {
2047 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
2050 template <typename Type_>
2051 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
2052 struct nlist &name(nl[index]);
2053 uintptr_t value(name.n_value);
2054 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
2055 value |= 0x00000001;
2056 function = reinterpret_cast<Type_>(value);
2059 template <typename Type_>
2060 static void dlset(Type_ &function, const char *name) {
2061 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
2064 // %hook CGImageReadCreateWithFile() {{{
2065 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
2067 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
2068 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2069 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
2074 MSHook(void *, CGImageSourceCreateWithFile, NSString *path, NSDictionary *options) {
2076 NSLog(@"WB:Debug: CGImageSourceCreateWithFile(%@, %@)", path, options);
2077 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2078 void *value(_CGImageSourceCreateWithFile([path wb$themedPath], options));
2083 MSHook(void *, CGImageSourceCreateWithURL, NSURL *url, NSDictionary *options) {
2085 NSLog(@"WB:Debug: CGImageSourceCreateWithURL(%@, %@)", url, options);
2086 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2087 if ([url isFileURL])
2088 url = [NSURL fileURLWithPath:[[url path] wb$themedPath]];
2089 void *value(_CGImageSourceCreateWithURL(url, options));
2095 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
2096 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
2097 if (style == nil || [style length] == 0)
2098 style = @"font-family: Helvetica; font-size: 12px";
2099 //NSLog(@"XXX:drawP(%@ | %@)", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
2100 [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
2103 static void NSString$drawInRect$withStyle$(NSString *self, SEL _cmd, CGRect rect, NSString *style) {
2104 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
2105 if (style == nil || [style length] == 0)
2106 style = @"font-family: Helvetica; font-size: 12px";
2107 //NSLog(@"XXX:drawR(%@ | %@)", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
2108 return [[WBMarkup sharedMarkup] drawString:self inRect:rect withStyle:style];
2111 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
2112 if (style == nil || [style length] == 0)
2113 style = @"font-family: Helvetica; font-size: 12px";
2114 CGSize size([[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width]);
2115 //NSLog(@"XXX:size(%@ | %@) = [%g %g]", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "], size.width, size.height);
2119 static void SBInitialize() {
2121 WBRename(SBApplication, pathForIcon, pathForIcon);
2122 WBRename(SBApplicationIcon, icon, icon);
2123 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
2126 WBRename(SBBookmarkIcon, icon, icon);
2127 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
2128 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
2129 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
2130 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
2132 WBRename(SBWidgetApplicationIcon, icon, icon);
2134 WBRename(SBDockIconListView, setFrame:, setFrame$);
2135 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
2137 if (kCFCoreFoundationVersionNumber < 600 || SummerBoard_)
2138 WBRename(SBIconLabel, drawRect:, drawRect$);
2139 else if (kCFCoreFoundationVersionNumber < 700) {
2140 WBRename(SBIconLabel, buildLabelImage, buildLabelImage);
2142 WBRename(SBIconLabelImageParameters, hash, hash);
2143 WBRename($SBIconView, _labelImageParametersForIcon:location:, _labelImageParametersForIcon$location$);
2144 WBRename($SBIconLabelImage, _drawLabelImageForParameters:, _drawLabelImageForParameters$);
2147 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
2148 WBRename(SBIconLabel, setInDock:, setInDock$);
2150 WBRename(SBIconList, didMoveToSuperview, didMoveToSuperview);
2151 WBRename(SBIconList, setFrame:, setFrame$);
2153 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
2154 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
2155 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
2156 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
2158 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
2159 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
2160 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
2162 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
2164 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
2165 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
2166 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
2167 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
2168 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
2169 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
2170 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
2171 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
2172 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
2175 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
2178 /*MSHook(int, open, const char *path, int oflag, mode_t mode) {
2179 int fd(_open(path, oflag, mode));
2181 static bool no(false);
2185 if (strstr(path, "/icon") != NULL)
2186 MSHookProcess(-1, "");
2188 if (fd == -1 && errno == EFAULT)
2189 NSLog(@"open(%p, %#x, %#o) = %d\n", path, oflag, mode, fd);
2191 NSLog(@"open(\"%s\", %#x, %#o) = %d\n", path, oflag, mode, fd);
2198 $objc_setAssociatedObject = reinterpret_cast<void (*)(id, void *, id value, objc_AssociationPolicy)>(dlsym(RTLD_DEFAULT, "objc_setAssociatedObject"));
2199 $objc_getAssociatedObject = reinterpret_cast<id (*)(id, void *)>(dlsym(RTLD_DEFAULT, "objc_getAssociatedObject"));
2200 $objc_removeAssociatedObjects = reinterpret_cast<void (*)(id)>(dlsym(RTLD_DEFAULT, "objc_removeAssociatedObjects"));
2202 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2204 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
2205 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
2207 Manager_ = [[NSFileManager defaultManager] retain];
2208 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
2210 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
2212 // Load Settings.plist {{{
2213 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
2214 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
2215 SummerBoard_ = [value boolValue];
2217 SummerBoard_ = true;
2219 if (NSNumber *value = [settings objectForKey:@"Debug"])
2220 Debug_ = [value boolValue];
2221 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
2222 UIDebug_ = [value boolValue];
2224 NSArray *themes([settings objectForKey:@"Themes"]);
2226 if (NSString *theme = [settings objectForKey:@"Theme"])
2227 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
2229 [NSNumber numberWithBool:true], @"Active",
2233 for (NSDictionary *theme in themes) {
2234 NSNumber *active([theme objectForKey:@"Active"]);
2235 if (![active boolValue])
2238 NSString *name([theme objectForKey:@"Name"]);
2242 NSString *theme(nil);
2244 #define testForTheme(format...) \
2245 if (theme == nil) { \
2246 NSString *path = [NSString stringWithFormat:format]; \
2247 if ([Manager_ fileExistsAtPath:path]) { \
2248 [Themes_ addObject:path]; \
2253 testForTheme(@"/Library/Themes/%@.theme", name)
2254 testForTheme(@"/Library/Themes/%@", name)
2255 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
2260 // Merge Info.plist {{{
2261 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2263 for (NSString *theme in Themes_)
2264 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
2265 for (NSString *key in [info allKeys])
2266 if ([Info_ objectForKey:key] == nil)
2267 [Info_ setObject:[info objectForKey:key] forKey:key];
2271 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
2272 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
2273 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
2276 // GraphicsServices {{{
2278 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
2282 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
2283 void *(*CGImageReadCreateWithFile)(NSString *, int);
2284 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
2285 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
2287 if (CGImageReadCreateWithFile == NULL) {
2288 void *(*CGImageSourceCreateWithFile)(NSString *, NSDictionary *);
2289 msset(CGImageSourceCreateWithFile, image, "_CGImageSourceCreateWithFile");
2290 MSHookFunction(CGImageSourceCreateWithFile, MSHake(CGImageSourceCreateWithFile));
2292 void *(*CGImageSourceCreateWithURL)(NSURL *, NSDictionary *);
2293 msset(CGImageSourceCreateWithURL, image, "_CGImageSourceCreateWithURL");
2294 MSHookFunction(CGImageSourceCreateWithURL, MSHake(CGImageSourceCreateWithURL));
2300 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
2301 Papered_ = $getTheme$(Wallpapers_) != nil;
2302 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
2304 CFNotificationCenterAddObserver(
2305 CFNotificationCenterGetDarwinNotifyCenter(),
2306 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
2309 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
2310 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
2311 if (MediaPlayer != nil)
2314 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
2315 $MPVideoView = objc_getClass("MPVideoView");
2322 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
2323 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
2324 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v28@0:4{CGRect={CGSize=ff}{CGSize=ff}}8@24");
2325 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
2327 if (kCFCoreFoundationVersionNumber > 700) { // XXX: iOS 6.x
2328 WBRename(UISharedArtwork, initWithName:inBundle:, initWithName$inBundle$);
2329 WBRename(UIImageTableArtwork, imageNamed:, imageNamed$);
2332 memset(nl, 0, sizeof(nl));
2333 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
2334 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
2335 nl[2].n_un.n_name = (char *) "__UIKitBundle";
2336 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
2337 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
2340 nlset(_UIApplicationImageWithName, nl, 0);
2341 nlset(_UIImageWithNameInDomain, nl, 1);
2342 nlset(_UIKitBundle, nl, 2);
2343 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
2344 nlset(_UISharedImageNameGetIdentifier, nl, 4);
2346 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
2347 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
2348 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
2353 //MSHookFunction(reinterpret_cast<int (*)(const char *, int, mode_t)>(&open), MSHake(open));
2355 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
2356 NSError *error(nil);
2357 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
2358 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
2360 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);