1 /* WinterBoard - Theme Manager for the iPhone
2 * Copyright (C) 2008-2011 Jay Freeman (saurik)
6 * Redistribution and use in source and binary
7 * forms, with or without modification, are permitted
8 * provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the
11 * above copyright notice, this list of conditions
12 * and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the
14 * above copyright notice, this list of conditions
15 * and the following disclaimer in the documentation
16 * and/or other materials provided with the
18 * 3. The name of the author may not be used to endorse
19 * or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
33 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 #define _trace() do { \
44 struct timeval _ctv; \
45 gettimeofday(&_ctv, NULL); \
50 NSLog(@"%lu.%.6u[%f]:WB:_trace()@%s:%u[%s]\n", \
51 _ctv.tv_sec, _ctv.tv_usec, \
52 (_ctv.tv_sec - _ltv.tv_sec) + (_ctv.tv_usec - _ltv.tv_usec) / 1000000.0, \
53 __FILE__, __LINE__, __FUNCTION__\
60 #import <CoreFoundation/CoreFoundation.h>
61 #import <Foundation/Foundation.h>
62 #import <CoreGraphics/CoreGraphics.h>
63 #import <ImageIO/CGImageSource.h>
65 #import <Celestial/AVController.h>
66 #import <Celestial/AVItem.h>
67 #import <Celestial/AVQueue.h>
69 #include <substrate.h>
71 #import <UIKit/UIKit.h>
73 #import <SpringBoard/SBApplication.h>
74 #import <SpringBoard/SBApplicationIcon.h>
75 #import <SpringBoard/SBAppWindow.h>
76 #import <SpringBoard/SBAwayView.h>
77 #import <SpringBoard/SBBookmarkIcon.h>
78 #import <SpringBoard/SBButtonBar.h>
79 #import <SpringBoard/SBCalendarIconContentsView.h>
80 #import <SpringBoard/SBIconController.h>
81 #import <SpringBoard/SBIconLabel.h>
82 #import <SpringBoard/SBIconList.h>
83 #import <SpringBoard/SBIconModel.h>
84 #import <SpringBoard/SBImageCache.h>
85 // XXX: #import <SpringBoard/SBSearchView.h>
86 #import <SpringBoard/SBSearchTableViewCell.h>
87 #import <SpringBoard/SBStatusBarContentsView.h>
88 #import <SpringBoard/SBStatusBarController.h>
89 #import <SpringBoard/SBStatusBarOperatorNameView.h>
90 #import <SpringBoard/SBStatusBarTimeView.h>
91 #import <SpringBoard/SBUIController.h>
92 #import <SpringBoard/SBWidgetApplicationIcon.h>
94 #import <MobileSMS/mSMSMessageTranscriptController.h>
96 #import <MediaPlayer/MPMoviePlayerController.h>
97 #import <MediaPlayer/MPVideoView.h>
98 #import <MediaPlayer/MPVideoView-PlaybackControl.h>
100 #import <CoreGraphics/CGGeometry.h>
102 #import <ChatKit/CKMessageCell.h>
104 #include <sys/sysctl.h>
106 #include "WBMarkup.h"
108 extern "C" void __clear_cache (char *beg, char *end);
110 @protocol WinterBoard
114 Class $MPMoviePlayerController;
117 MSClassHook(NSBundle)
118 MSClassHook(NSString)
121 MSMetaClassHook(UIImage)
122 MSClassHook(UINavigationBar)
123 MSClassHook(UIToolbar)
124 MSClassHook(UIStatusBarTimeItemView)
125 MSClassHook(UIWebDocumentView)
127 MSClassHook(CKBalloonView)
128 MSClassHook(CKMessageCell)
129 MSClassHook(CKTimestampView)
130 MSClassHook(CKTranscriptCell)
131 MSClassHook(CKTranscriptController)
132 MSClassHook(CKTranscriptHeaderView)
133 MSClassHook(CKTranscriptTableView)
135 MSClassHook(SBApplication)
136 MSClassHook(SBApplicationIcon)
137 MSClassHook(SBAwayView)
138 MSClassHook(SBBookmarkIcon)
139 MSClassHook(SBButtonBar)
140 MSClassHook(SBCalendarApplicationIcon)
141 MSClassHook(SBCalendarIconContentsView)
142 MSClassHook(SBDockIconListView)
144 MSClassHook(SBIconBadge)
145 MSClassHook(SBIconBadgeFactory)
146 MSClassHook(SBIconContentView)
147 MSClassHook(SBIconController)
148 MSClassHook(SBIconLabel)
149 MSClassHook(SBIconList)
150 MSClassHook(SBIconModel)
151 //MSClassHook(SBImageCache)
152 MSClassHook(SBSearchView)
153 MSClassHook(SBSearchTableViewCell)
154 MSClassHook(SBSlidingAlertDisplay)
155 MSClassHook(SBStatusBarContentsView)
156 MSClassHook(SBStatusBarController)
157 MSClassHook(SBStatusBarOperatorNameView)
158 MSClassHook(SBStatusBarTimeView)
159 MSClassHook(SBUIController)
160 MSClassHook(SBWallpaperView)
161 MSClassHook(SBWidgetApplicationIcon)
163 extern "C" void WKSetCurrentGraphicsContext(CGContextRef);
165 static struct MSFixClass { MSFixClass() {
166 $UIWebDocumentView = objc_getClass("UIWebBrowserView") ?: $UIWebDocumentView;
167 $SBIcon = objc_getClass("SBIconView") ?: $SBIcon;
169 if ($SBIconList == nil)
170 $SBIconList = objc_getClass("SBIconListView");
171 if ($CKTranscriptController == nil)
172 $CKTranscriptController = objc_getClass("mSMSMessageTranscriptController");
176 static bool Four_($SBDockIconListView != nil);
178 @interface NSDictionary (WinterBoard)
179 - (UIColor *) wb$colorForKey:(NSString *)key;
180 - (BOOL) wb$boolForKey:(NSString *)key;
183 @implementation NSDictionary (WinterBoard)
185 - (UIColor *) wb$colorForKey:(NSString *)key {
186 NSString *value = [self objectForKey:key];
193 - (BOOL) wb$boolForKey:(NSString *)key {
194 if (NSString *value = [self objectForKey:key])
195 return [value boolValue];
201 static BOOL (*_GSFontGetUseLegacyFontMetrics)();
202 #define $GSFontGetUseLegacyFontMetrics() \
203 (_GSFontGetUseLegacyFontMetrics == NULL ? YES : _GSFontGetUseLegacyFontMetrics())
205 static bool Debug_ = false;
206 static bool UIDebug_ = false;
207 static bool Engineer_ = false;
208 static bool SummerBoard_ = false;
209 static bool SpringBoard_;
211 static UIImage *(*_UIApplicationImageWithName)(NSString *name);
212 static UIImage *(*_UIImageWithNameInDomain)(NSString *name, NSString *domain);
213 static NSBundle *(*_UIKitBundle)();
214 static bool (*_UIPackedImageTableGetIdentifierForName)(NSString *, int *);
215 static int (*_UISharedImageNameGetIdentifier)(NSString *);
217 static NSMutableDictionary *UIImages_ = [[NSMutableDictionary alloc] initWithCapacity:32];
218 static NSMutableDictionary *PathImages_ = [[NSMutableDictionary alloc] initWithCapacity:16];
219 static NSMutableDictionary *Cache_ = [[NSMutableDictionary alloc] initWithCapacity:64];
220 static NSMutableDictionary *Strings_ = [[NSMutableDictionary alloc] initWithCapacity:0];
221 static NSMutableDictionary *Bundles_ = [[NSMutableDictionary alloc] initWithCapacity:2];
223 static NSFileManager *Manager_;
224 static NSMutableArray *Themes_;
226 static NSDictionary *English_;
227 static NSMutableDictionary *Info_;
230 static NSMutableDictionary *Themed_ = [[NSMutableDictionary alloc] initWithCapacity:128];
232 static unsigned Scale_ = 0;
234 static unsigned $getScale$(NSString *path) {
235 NSString *name(path);
237 #define StripName(strip) \
238 if ([name hasSuffix:@ strip]) \
239 name = [name substringWithRange:NSMakeRange(0, [name length] - sizeof(strip) - 1)];
243 StripName("~iphone");
246 return [name hasSuffix:@"@2x"] ? 2 : 1;
249 static NSArray *$useScale$(NSArray *files, bool use = true) {
250 if (use && Scale_ == 0) {
251 UIScreen *screen([UIScreen mainScreen]);
252 if ([screen respondsToSelector:@selector(scale)])
253 Scale_ = [screen scale];
261 NSString *idiom(IsWild_ ? @"ipad" : @"iphone");
263 NSMutableArray *scaled([NSMutableArray arrayWithCapacity:([files count] * 4)]);
265 for (NSString *file in files) {
266 NSString *base([file stringByDeletingPathExtension]);
267 NSString *extension([file pathExtension]);
271 [scaled addObject:[NSString stringWithFormat:@"%@@2x~%@.%@", base, idiom, extension]];
273 [scaled addObject:[NSString stringWithFormat:@"%@@2x.%@", base, extension]];
276 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
278 // if (!IsWild_) <- support old themes
279 [scaled addObject:file];
280 } else if ([base hasSuffix: @"@2x"]) {
281 [scaled addObject:[NSString stringWithFormat:@"%@~iphone.%@", base, extension]];
282 [scaled addObject:file];
284 // XXX: this actually can't be used, as the person loading the file doesn't realize that the @2x changed
285 /*NSString *rest([base substringWithRange:NSMakeRange(0, [base length] - 3)]);
286 [scaled addObject:[NSString stringWithFormat:@"%@~iphone.%@", rest, extension]];
287 [scaled addObject:[rest stringByAppendingPathExtension:extension]];*/
289 // XXX: this code isn't really complete
291 [scaled addObject:file];
293 if ([base hasSuffix:@"~iphone"])
294 [scaled addObject:[[base substringWithRange:NSMakeRange(0, [base length] - 7)] stringByAppendingPathExtension:extension]];
301 static NSString *$getTheme$(NSArray *files, NSArray *themes = Themes_) {
302 // XXX: this is not reasonable; OMG
305 @synchronized (Themed_) {
306 if (NSString *path = [Themed_ objectForKey:key])
307 return reinterpret_cast<id>(path) == [NSNull null] ? nil : path;
311 NSLog(@"WB:Debug: %@", [files description]);
315 for (NSString *theme in Themes_)
316 for (NSString *file in files) {
317 path = [NSString stringWithFormat:@"%@/%@", theme, file];
318 if ([Manager_ fileExistsAtPath:path])
325 @synchronized (Themed_) {
326 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:key];
332 // $pathForFile$inBundle$() {{{
333 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool ui) {
334 NSString *identifier = [bundle bundleIdentifier];
335 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
337 if (identifier != nil)
338 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
339 if (NSString *folder = [[bundle bundlePath] lastPathComponent]) {
340 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
341 NSString *base([folder stringByDeletingPathExtension]);
342 if ([base hasSuffix:@"~iphone"])
343 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 7)], [folder pathExtension], file]];
346 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
348 #define remapResourceName(oldname, newname) \
349 else if ([file isEqualToString:(oldname)]) \
350 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
352 bool summer(SpringBoard_ && SummerBoard_);
354 if (identifier == nil);
355 else if ([identifier isEqualToString:@"com.apple.chatkit"])
356 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
357 else if ([identifier isEqualToString:@"com.apple.calculator"])
358 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
360 remapResourceName(@"FSO_BG.png", @"StatusBar")
361 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
362 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
364 [names addObject:[NSString stringWithFormat:@"Fallback/%@", file]];
366 if (NSString *path = $getTheme$($useScale$(names, ui)))
373 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
374 NSString *identifier = [self bundleIdentifier];
375 NSString *path = [self path];
376 NSString *folder = [path lastPathComponent];
377 NSString *dname = [self displayName];
378 NSString *didentifier = [self displayIdentifier];
381 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
383 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
385 /* XXX: I might need to keep this for backwards compatibility
386 if (identifier != nil)
387 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
389 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
391 #define testForIcon(Name) \
392 if (NSString *name = Name) \
393 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
395 if (![didentifier isEqualToString:identifier])
396 testForIcon(didentifier);
398 testForIcon(identifier);
401 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
404 if (didentifier != nil) {
405 testForIcon([English_ objectForKey:didentifier]);
407 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
408 if ([parts count] != 1)
409 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
410 testForIcon([english objectForKey:[parts lastObject]]);
413 if (NSString *path = $getTheme$(names))
419 // -[NSBundle wb$bundleWithFile] {{{
420 @interface NSBundle (WinterBoard)
421 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
424 @implementation NSBundle (WinterBoard)
426 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
427 path = [path stringByDeletingLastPathComponent];
428 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
431 NSBundle *bundle([Bundles_ objectForKey:path]);
432 if (reinterpret_cast<id>(bundle) == [NSNull null])
434 else if (bundle == nil) {
435 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
436 bundle = [NSBundle bundleWithPath:path];
438 bundle = [NSBundle wb$bundleWithFile:path];
440 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
441 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
449 // -[NSString wb$themedPath] {{{
450 @interface NSString (WinterBoard)
451 - (NSString *) wb$themedPath;
454 @implementation NSString (WinterBoard)
456 - (NSString *) wb$themedPath {
457 if ([self hasPrefix:@"/Library/Themes/"])
461 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
463 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
464 NSString *file([self stringByResolvingSymlinksInPath]);
465 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
466 if ([file hasPrefix:prefix]) {
467 NSUInteger length([prefix length]);
468 if (length != [file length])
469 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
480 void WBLogRect(const char *tag, struct CGRect rect) {
481 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
484 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
485 CGRect frame([view frame]);
486 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]);
488 for (UIView *child in [view subviews])
489 WBLogHierarchy(child, index++, indent + 1);
492 UIImage *$cacheForImage$(UIImage *image) {
493 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
494 CGRect rect = {CGPointMake(1, 1), [image size]};
495 CGSize size = {rect.size.width + 2, rect.size.height + 2};
497 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
498 CGColorSpaceRelease(space);
500 CGContextDrawImage(context, rect, [image CGImage]);
501 CGImageRef ref(CGBitmapContextCreateImage(context));
502 CGContextRelease(context);
504 UIImage *cache([UIImage imageWithCGImage:ref]);
510 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
511 //if ([name isEqualToString:@"icons"]) return nil;
512 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
515 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
516 NSString *key([icon displayIdentifier]);
518 if (UIImage *image = [icon icon]) {
519 CGSize size = [image size];
520 if (size.width != 59 || size.height != 60) {
521 UIImage *cache($cacheForImage$(image));
522 [Cache_ setObject:cache forKey:key];
527 _SBIconModel$cacheImageForIcon$(self, sel, icon);
530 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
531 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
532 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
534 NSString *key([icon displayIdentifier]);
536 if (UIImage *image = [icon icon]) {
537 CGSize size = [image size];
538 if (size.width != 59 || size.height != 60) {
539 UIImage *cache($cacheForImage$(image));
540 [Cache_ setObject:cache forKey:key];
546 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
547 NSString *key([icon displayIdentifier]);
548 if (UIImage *image = [Cache_ objectForKey:key])
551 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
554 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
556 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
557 NSString *key([icon displayIdentifier]);
558 if (UIImage *image = [Cache_ objectForKey:key])
561 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
564 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
565 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
566 [self setBackgroundColor:[UIColor clearColor]];
567 for (UIView *child in [self subviews])
568 [child setBackgroundColor:[UIColor clearColor]];
572 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
573 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
574 [self setBackgroundColor:[UIColor clearColor]];
578 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
579 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
580 float inset([self edgeInset]);
581 [[UIColor clearColor] set];
582 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
583 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
586 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
587 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
588 if (NSString *path = $pathForIcon$([self application]))
589 return [UIImage imageWithContentsOfFile:path];
590 return _SBApplicationIcon$icon(self, sel);
593 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
595 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
596 if (IsWild_ && false) // XXX: delete this code, it should not be supported
597 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
598 return [UIImage imageWithContentsOfFile:path72];
599 if (NSString *path = $pathForIcon$([self application]))
600 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
602 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
603 width = [$SBIcon defaultIconImageSize].width;
606 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
609 return _SBApplicationIcon$generateIconImage$(self, sel, type);
612 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
614 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
615 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
616 return [UIImage imageWithContentsOfFile:path];
617 return _SBWidgetApplicationIcon$icon(self, sel);
620 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
622 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
623 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
624 return [UIImage imageWithContentsOfFile:path];
625 return _SBBookmarkIcon$icon(self, sel);
628 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
629 if (NSString *path = $pathForIcon$(self))
631 return _SBApplication$pathForIcon(self, sel);
634 static UIImage *CachedImageAtPath(NSString *path) {
635 path = [path stringByResolvingSymlinksInPath];
636 UIImage *image = [PathImages_ objectForKey:path];
638 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
639 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
641 image = [image autorelease];
642 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
646 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
647 NSBundle *bundle = [NSBundle mainBundle];
649 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
650 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
651 return CachedImageAtPath(path);
652 return __UIApplicationImageWithName(name);
655 #define WBDelegate(delegate) \
656 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
658 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
659 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
661 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
665 - (void) forwardInvocation:(NSInvocation*)inv { \
666 SEL sel = [inv selector]; \
667 if ([delegate respondsToSelector:sel]) \
668 [inv invokeWithTarget:delegate]; \
670 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
673 // %hook -[NSBundle pathForResource:ofType:] {{{
674 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
675 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
677 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
678 if (NSString *path = $pathForFile$inBundle$(file, self, false))
680 return MSOldCall(resource, type);
684 static void $drawLabel$(NSString *label, CGRect rect, NSString *style, NSString *custom) {
685 bool ellipsis(false);
686 float max = rect.size.width - 11, width;
688 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
691 size_t length([label length]);
692 float spacing((width - max) / (length - 1));
694 if (spacing > 1.25) {
696 label = [label substringToIndex:(length - 1)];
700 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
704 label = [label stringByAppendingString:@"..."];
707 style = [style stringByAppendingString:custom];
709 CGSize size = [label sizeWithStyle:style forWidth:rect.size.width];
710 [label drawAtPoint:CGPointMake((rect.size.width - size.width) / 2 + rect.origin.x, rect.origin.y) withStyle:style];
713 static struct WBStringDrawingState {
714 WBStringDrawingState *next_;
718 } *stringDrawingState_;
720 extern "C" CGColorSpaceRef CGContextGetFillColorSpace(CGContextRef);
721 extern "C" void CGContextGetFillColor(CGContextRef, CGFloat[]);
723 static NSString *WBColorMarkup() {
724 CGContextRef context(UIGraphicsGetCurrentContext());
725 //NSLog(@"XXX:1:%p", context);
729 CGColorSpaceRef space(CGContextGetFillColorSpace(context));
730 //NSLog(@"XXX:2:%p", space);
734 size_t number(CGColorSpaceGetNumberOfComponents(space));
735 //NSLog(@"XXX:3:%u", number);
739 CGFloat components[number + 1];
740 CGContextGetFillColor(context, components);
763 return [NSString stringWithFormat:@"color: rgba(%g, %g, %g, %g)", r * 255, g * 255, b * 255, a];
766 MSInstanceMessageHook6(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode,letterSpacing,includeEmoji, CGPoint, point, float, width, UIFont *, font, UILineBreakMode, mode, float, spacing, BOOL, emoji) {
767 //NSLog(@"XXX: @\"%@\" %g", self, spacing);
769 WBStringDrawingState *state(stringDrawingState_);
771 return MSOldCall(point, width, font, mode, spacing, emoji);
773 if (--state->count_ == 0)
774 stringDrawingState_ = state->next_;
775 if (state->info_ == nil)
776 return MSOldCall(point, width, font, mode, spacing, emoji);
778 NSString *info([Info_ objectForKey:state->info_]);
780 return MSOldCall(point, width, font, mode, spacing, emoji);
782 NSString *base(state->base_ ?: @"");
783 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
784 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
788 extern "C" NSString *NSStringFromCGRect(CGRect rect);
790 MSInstanceMessageHook7(CGSize, NSString, _drawInRect,withFont,lineBreakMode,alignment,lineSpacing,includeEmoji,truncationRect, CGRect, rect, UIFont *, font, UILineBreakMode, mode, UITextAlignment, alignment, float, spacing, BOOL, emoji, CGRect, truncation) {
791 //NSLog(@"XXX: &\"%@\" %@ \"%@\" %u %u %g %u %@", self, NSStringFromCGRect(rect), font, mode, alignment, spacing, emoji, NSStringFromCGRect(truncation));
793 WBStringDrawingState *state(stringDrawingState_);
795 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
797 if (--state->count_ == 0)
798 stringDrawingState_ = state->next_;
799 if (state->info_ == nil)
800 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
802 NSString *info([Info_ objectForKey:state->info_]);
804 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
809 case UITextAlignmentLeft:
812 case UITextAlignmentCenter:
813 textAlign = @"center";
815 case UITextAlignmentRight:
816 textAlign = @"right";
820 NSString *base(state->base_ ?: @"");
821 NSString *extra([NSString stringWithFormat:@"text-align: %@", textAlign]);
824 $drawLabel$(self, rect, [NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], WBColorMarkup(), base], info);
826 [self drawInRect:rect withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
831 MSInstanceMessageHook4(CGSize, NSString, sizeWithFont,forWidth,lineBreakMode,letterSpacing, UIFont *, font, float, width, UILineBreakMode, mode, float, spacing) {
832 //NSLog(@"XXX: #\"%@\" \"%@\" %g %u %g", self, font, width, mode, spacing);
834 WBStringDrawingState *state(stringDrawingState_);
836 return MSOldCall(font, width, mode, spacing);
838 if (--state->count_ == 0)
839 stringDrawingState_ = state->next_;
840 if (state->info_ == nil)
841 return MSOldCall(font, width, mode, spacing);
843 NSString *info([Info_ objectForKey:state->info_]);
845 return MSOldCall(font, width, mode, spacing);
847 NSString *base(state->base_ ?: @"");
848 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
849 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info] forWidth:width];
852 MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) {
853 //NSLog(@"XXX: ?\"%@\"", self);
855 WBStringDrawingState *state(stringDrawingState_);
857 return MSOldCall(font);
859 if (--state->count_ == 0)
860 stringDrawingState_ = state->next_;
861 if (state->info_ == nil)
862 return MSOldCall(font);
864 NSString *info([Info_ objectForKey:state->info_]);
866 return MSOldCall(font);
868 NSString *base(state->base_ ?: @"");
869 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), base, info] forWidth:65535];
872 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
873 WBStringDrawingState badgeState = {NULL, 1, @""
876 stringDrawingState_ = &badgeState;
878 UIImage *image(MSOldCall(text));
880 stringDrawingState_ = NULL;
884 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
885 WBStringDrawingState dayState = {NULL, 2, @""
886 // XXX: this is only correct on an iPod dock
887 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
888 , @"CalendarIconDayStyle"};
890 WBStringDrawingState sizeState = {&dayState, 7, nil, nil};
892 WBStringDrawingState dateState = {&sizeState, 2, @""
893 , @"CalendarIconDateStyle"};
895 stringDrawingState_ = &dateState;
897 UIImage *image(MSOldCall(type));
899 stringDrawingState_ = NULL;
903 MSInstanceMessageHook1(UIImage *, UIStatusBarTimeItemView, contentsImageForStyle, int, style) {
904 WBStringDrawingState timeState = {NULL, 0, @""
907 stringDrawingState_ = &timeState;
909 UIImage *image(MSOldCall(style));
911 stringDrawingState_ = NULL;
915 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
916 NSBundle *bundle([NSBundle mainBundle]);
918 CFLocaleRef locale(CFLocaleCopyCurrent());
919 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
922 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
924 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
925 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
926 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
927 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
931 CFRelease(formatter);
933 NSString *datestyle([@""
934 "font-family: Helvetica; "
935 "font-weight: bold; "
938 "" stringByAppendingString:(IsWild_
939 ? @"font-size: 54px; "
940 : @"font-size: 39px; "
943 NSString *daystyle([@""
944 "font-family: Helvetica; "
945 "font-weight: bold; "
947 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
948 "" stringByAppendingString:(IsWild_
949 ? @"font-size: 11px; "
950 : @"font-size: 9px; "
953 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
954 datestyle = [datestyle stringByAppendingString:style];
955 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
956 daystyle = [daystyle stringByAppendingString:style];
958 float width([self bounds].size.width);
960 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
961 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
963 unsigned base0(IsWild_ ? 89 : 70);
964 if ($GSFontGetUseLegacyFontMetrics())
966 unsigned base1(IsWild_ ? 18 : 16);
973 [(NSString *)date drawAtPoint:CGPointMake(
974 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
975 ) withStyle:datestyle];
977 [(NSString *)day drawAtPoint:CGPointMake(
978 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
979 ) withStyle:daystyle];
985 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
986 void $setBarStyle$_(NSString *name, int &style) {
988 NSLog(@"WB:Debug:%@Style:%d", name, style);
989 NSNumber *number = nil;
991 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
993 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
995 style = [number intValue];
997 NSLog(@"WB:Debug:%@Style=%d", name, style);
1001 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
1002 $setBarStyle$_(@"Toolbar", style);
1003 return MSOldCall(style);
1006 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
1007 $setBarStyle$_(@"NavigationBar", style);
1008 return MSOldCall(style);
1012 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
1013 [[self superview] setBackgroundColor:[UIColor clearColor]];
1014 _SBButtonBar$didMoveToSuperview(self, sel);
1017 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
1018 [[self superview] setBackgroundColor:[UIColor clearColor]];
1019 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
1022 static NSArray *Wallpapers_;
1023 static bool Papered_;
1024 static bool Docked_;
1025 static bool SMSBackgrounded_;
1026 static NSString *WallpaperFile_;
1027 static UIImageView *WallpaperImage_;
1028 static UIWebDocumentView *WallpaperPage_;
1029 static NSURL *WallpaperURL_;
1031 #define _release(object) \
1032 do if (object != nil) { \
1037 static UIImage *$getImage$(NSString *path) {
1038 UIImage *image([UIImage imageWithContentsOfFile:path]);
1040 unsigned scale($getScale$(path));
1041 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
1042 [image setScale:scale];
1047 static UIImage *$getDefaultDesktopImage$() {
1048 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
1049 return $getImage$(path);
1053 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
1054 return $getDefaultDesktopImage$() ?: MSOldCall();
1057 MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
1058 return $getDefaultDesktopImage$() ?: MSOldCall();
1061 MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
1062 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
1063 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
1064 if (UIImage *image = $getDefaultDesktopImage$()) {
1065 [self setImage:image];
1075 // %hook -[SBUIController init] {{{
1076 MSInstanceMessageHook0(id, SBUIController, init) {
1081 NSString *paper($getTheme$(Wallpapers_));
1083 paper = [paper stringByDeletingLastPathComponent];
1087 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
1088 char *machine = new char[size];
1090 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
1091 perror("sysctlbyname(\"hw.machine\", ?)");
1096 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
1100 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
1103 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
1104 if (&_wallpaperView != NULL) {
1105 [_wallpaperView removeFromSuperview];
1106 [_wallpaperView release];
1107 _wallpaperView = nil;
1111 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
1112 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
1115 if (&_contentLayer != NULL)
1116 player = &_contentLayer;
1117 else if (&_contentView != NULL)
1118 player = &_contentView;
1121 UIView *layer(player == NULL ? nil : *player);
1123 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
1124 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
1125 [window setContentView:content];
1127 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
1128 [window setBackgroundColor:[_window backgroundColor]];
1129 [_window setBackgroundColor:[UIColor clearColor]];
1131 [window setLevel:-1000];
1132 [window setHidden:NO];
1134 /*if (player != NULL)
1135 *player = content;*/
1137 [content setBackgroundColor:[layer backgroundColor]];
1138 [layer setBackgroundColor:[UIColor clearColor]];
1141 if (!SummerBoard_ || !IsWild_)
1144 CGRect bounds([content bounds]);
1145 bounds.origin.y = -30;
1146 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
1147 [content addSubview:indirect];
1148 [indirect zoomToScale:2.4];
1151 _release(WallpaperFile_);
1152 _release(WallpaperImage_);
1153 _release(WallpaperPage_);
1154 _release(WallpaperURL_);
1157 NSArray *themes([NSArray arrayWithObject:paper]);
1159 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1163 static AVController *controller_(nil);
1164 if (controller_ == nil) {
1165 AVQueue *queue([AVQueue avQueue]);
1166 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1169 AVQueue *queue([controller_ queue]);
1171 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1172 [controller_ setLayer:[video _layer]];
1174 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1175 [queue appendItem:item error:&error];
1177 [controller_ play:&error];
1178 #elif UseMPMoviePlayerController
1179 NSURL *url([NSURL fileURLWithPath:path]);
1180 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1181 controller.movieControlMode = MPMovieControlModeHidden;
1184 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1185 [video setMovieWithPath:path];
1186 [video setRepeatMode:1];
1187 [video setRepeatGap:-1];
1188 [video playFromBeginning];;
1191 [indirect addSubview:video];
1194 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1195 if (UIImage *image = $getImage$(path)) {
1196 WallpaperFile_ = [path retain];
1197 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1198 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1199 [WallpaperImage_ setAlpha:[number floatValue]];
1200 [indirect addSubview:WallpaperImage_];
1204 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1205 CGRect bounds = [indirect bounds];
1207 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1208 [view setAutoresizes:true];
1210 WallpaperPage_ = [view retain];
1211 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1213 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1215 [view setBackgroundColor:[UIColor clearColor]];
1216 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1217 [view setDrawsBackground:NO];
1218 [[view webView] setDrawsBackground:NO];
1220 [indirect addSubview:view];
1224 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1225 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1226 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1227 if ([Manager_ fileExistsAtPath:html]) {
1228 CGRect bounds = [indirect bounds];
1230 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1231 [view setAutoresizes:true];
1233 NSURL *url = [NSURL fileURLWithPath:html];
1234 [view loadRequest:[NSURLRequest requestWithURL:url]];
1236 [view setBackgroundColor:[UIColor clearColor]];
1237 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1238 [view setDrawsBackground:NO];
1239 [[view webView] setDrawsBackground:NO];
1241 [indirect addSubview:view];
1249 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1250 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1251 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1253 if (path != nil && _backgroundView != nil)
1256 _SBAwayView$updateDesktopImage$(self, sel, image);
1259 CGRect bounds = [self bounds];
1261 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1262 [view setAutoresizes:true];
1264 if (WallpaperPage_ != nil)
1265 [WallpaperPage_ release];
1266 WallpaperPage_ = [view retain];
1268 if (WallpaperURL_ != nil)
1269 [WallpaperURL_ release];
1270 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1272 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1274 [[view webView] setDrawsBackground:false];
1275 [view setBackgroundColor:[UIColor clearColor]];
1277 [self insertSubview:view aboveSubview:_backgroundView];
1281 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1282 extern "C" CGColorRef CGGStateGetFillColor(void *);
1283 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1284 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1286 /* WBTimeLabel {{{ */
1287 @interface WBTimeLabel : NSProxy {
1289 _transient SBStatusBarTimeView *view_;
1292 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1296 @implementation WBTimeLabel
1303 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1304 time_ = [time retain];
1309 - (NSString *) description {
1315 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1316 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1317 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1319 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1320 "font-family: Helvetica; "
1321 "font-weight: bold; "
1324 "%@", _mode ? @"white" : @"black", custom]];
1329 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1334 /* WBBadgeLabel {{{ */
1335 @interface WBBadgeLabel : NSProxy {
1339 - (id) initWithBadge:(NSString *)badge;
1340 - (NSString *) description;
1344 @implementation WBBadgeLabel
1351 - (id) initWithBadge:(NSString *)badge {
1352 badge_ = [badge retain];
1356 - (NSString *) description {
1357 return [badge_ description];
1362 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1363 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1364 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1365 "font-family: Helvetica; "
1366 "font-weight: bold; "
1374 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1381 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1382 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1383 alpha = [number floatValue];
1384 return MSOldCall(alpha);
1387 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1388 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1389 alpha = [number floatValue];
1390 return MSOldCall(alpha);
1393 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1394 if ((self = MSOldCall()) != nil) {
1395 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1396 // XXX: note: this is overridden above, which is silly
1397 float alpha([number floatValue]);
1398 if ([self respondsToSelector:@selector(setIconImageAlpha:)])
1399 [self setIconImageAlpha:alpha];
1400 if ([self respondsToSelector:@selector(setIconLabelAlpha:)])
1401 [self setIconLabelAlpha:alpha];
1402 if ([self respondsToSelector:@selector(setAlpha:)])
1403 [self setAlpha:alpha];
1408 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1409 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1410 alpha = [number floatValue];
1411 return MSOldCall(alpha);
1415 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1416 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1417 id &_badge(MSHookIvar<id>(self, "_badge"));
1419 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1424 void SBStatusBarController$setStatusBarMode(int &mode) {
1426 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1427 if (mode < 100) // 104:hidden 105:glowing
1428 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1429 mode = [number intValue];
1432 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1433 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1434 SBStatusBarController$setStatusBarMode(mode);
1435 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1438 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1439 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1440 SBStatusBarController$setStatusBarMode(mode);
1441 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1444 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) {
1445 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1446 SBStatusBarController$setStatusBarMode(mode);
1447 //NSLog(@"mode=%u", mode);
1448 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1451 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1452 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1453 mode = [number intValue];
1454 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1457 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1458 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1460 NSLog(@"operatorNameStyle= %@", style);
1461 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1462 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1466 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1468 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1469 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1472 // XXX: replace this with [SBStatusBarTimeView tile]
1473 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1474 id &_time(MSHookIvar<id>(self, "_time"));
1475 if (_time != nil && [_time class] != [WBTimeLabel class])
1476 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1477 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1480 @interface UIView (WinterBoard)
1481 - (bool) wb$isWBImageView;
1482 - (void) wb$logHierarchy;
1483 - (void) wb$setBackgroundColor:(UIColor *)color;
1486 @implementation UIView (WinterBoard)
1488 - (bool) wb$isWBImageView {
1492 - (void) wb$logHierarchy {
1493 WBLogHierarchy(self);
1496 - (void) wb$setBackgroundColor:(UIColor *)color {
1497 [self setBackgroundColor:color];
1498 for (UIView *child in [self subviews])
1499 [child wb$setBackgroundColor:color];
1504 @interface WBImageView : UIImageView {
1507 - (bool) wb$isWBImageView;
1508 - (void) wb$updateFrame;
1511 @implementation WBImageView
1513 - (bool) wb$isWBImageView {
1517 - (void) wb$updateFrame {
1518 CGRect frame([self frame]);
1521 for (UIView *view(self); ; ) {
1522 view = [view superview];
1525 frame.origin.y -= [view frame].origin.y;
1528 [self setFrame:frame];
1533 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1534 NSArray *subviews([self subviews]);
1535 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1536 if (view != nil && [view wb$isWBImageView])
1537 [view wb$updateFrame];
1538 _SBIconList$setFrame$(self, sel, frame);
1541 static void $addPerPageView$(unsigned i, UIView *list) {
1542 NSString *path($getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]]));
1546 NSArray *subviews([list subviews]);
1548 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1549 if (view == nil || ![view wb$isWBImageView]) {
1550 view = [[[WBImageView alloc] init] autorelease];
1551 [list insertSubview:view atIndex:0];
1554 UIImage *image([UIImage imageWithContentsOfFile:path]);
1556 CGRect frame([view frame]);
1557 frame.size = [image size];
1558 [view setFrame:frame];
1560 [view setImage:image];
1561 [view wb$updateFrame];
1564 static void $addPerPageViews$(NSArray *lists) {
1565 for (unsigned i(0), e([lists count]); i != e; ++i)
1566 $addPerPageView$(i, [lists objectAtIndex:i]);
1569 MSInstanceMessageHook0(void, SBIconController, updateNumberOfRootIconLists) {
1570 NSArray *&_rootIconLists(MSHookIvar<NSArray *>(self, "_rootIconLists"));
1571 $addPerPageViews$(_rootIconLists);
1575 MSInstanceMessageHook0(void, SBIconContentView, layoutSubviews) {
1578 if (SBIconController *controller = [$SBIconController sharedInstance]) {
1579 UIView *&_dockContainerView(MSHookIvar<UIView *>(controller, "_dockContainerView"));
1580 if (&_dockContainerView != NULL)
1581 [[_dockContainerView superview] bringSubviewToFront:_dockContainerView];
1585 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1586 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1587 $addPerPageViews$([_iconModel iconLists]);
1588 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1591 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1592 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1594 [self setClipsToBounds:NO];
1598 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1599 static bool gssc(false);
1601 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1602 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1605 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1606 [Info_ setObject:[NSNumber numberWithBool:(
1608 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1609 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1610 )] forKey:@"UndockedIconLabels"];
1613 id &_label(MSHookIvar<id>(self, "_label"));
1614 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1617 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1618 [_label setInDock:docked];
1620 _SBIconLabel$setInDock$(self, sel, docked);
1621 [self setNeedsDisplay];
1624 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1625 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1628 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1629 _SBDockIconListView$setFrame$(self, sel, frame);
1632 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1633 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1634 NSString *identifier = [self bundleIdentifier];
1635 NSLocale *locale = [NSLocale currentLocale];
1636 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1638 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1639 NSString *file = table == nil ? @"Localizable" : table;
1640 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1641 NSDictionary *strings;
1642 if ((strings = [Strings_ objectForKey:name]) != nil) {
1643 if (static_cast<id>(strings) != [NSNull null]) strings:
1644 if (NSString *value = [strings objectForKey:key])
1646 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1649 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1650 [Strings_ setObject:[strings autorelease] forKey:name];
1654 [Strings_ setObject:[NSNull null] forKey:name];
1655 return MSOldCall(key, value, table);
1658 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1659 MSClassHook(WebCoreFrameBridge)
1661 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1664 void **core(reinterpret_cast<void **>([node _node]));
1665 if (core == NULL || core[6] == NULL)
1667 return MSOldCall(node, width);
1671 MSInstanceMessage1(void, SBIconLabel, drawRect, CGRect, rect) {
1672 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1675 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1676 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1678 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1680 NSString *style = [NSString stringWithFormat:@""
1681 "font-family: Helvetica; "
1682 "font-weight: bold; "
1684 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1685 ? @"font-size: 12px; "
1686 : @"font-size: 11px; "
1690 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1692 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1694 NSString *custom([Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")]);
1696 $drawLabel$(label, [self bounds], style, custom);
1699 MSInstanceMessage0(CGImageRef, SBIconLabel, buildLabelImage) {
1700 bool docked((MSHookIvar<unsigned>(self, "_inDock") & 0x2) != 0);
1702 WBStringDrawingState labelState = {NULL, 0, @""
1703 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1705 stringDrawingState_ = &labelState;
1708 CGImageRef image(MSOldCall());
1711 stringDrawingState_ = NULL;
1716 MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1717 if ((self = MSOldCall(frame, delegate)) != nil) {
1718 [self setBackgroundColor:[UIColor clearColor]];
1722 MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1723 return SMSBackgrounded_ ? NO : MSOldCall();
1726 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1727 [self wb$setBackgroundColor:[UIColor clearColor]];
1731 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1733 [balloon setBackgroundColor:[UIColor clearColor]];
1736 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1737 MSOldCall([UIColor clearColor]);
1738 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1742 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1743 if ((self = MSOldCall(style, reuse)) != nil) {
1744 [self setBackgroundColor:[UIColor clearColor]];
1745 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1750 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1751 if ((self = MSOldCall(style, reuse)) != nil) {
1752 [self setBackgroundColor:[UIColor clearColor]];
1753 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1757 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1758 if ((self = MSOldCall(style, reuse)) != nil) {
1759 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1760 [_label setBackgroundColor:[UIColor clearColor]];
1764 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1765 MSOldCall(UITableViewCellSeparatorStyleNone);
1768 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1769 if ((self = MSOldCall(frame, style)) != nil) {
1770 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1774 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1777 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1778 if (UIImage *image = $getImage$(path)) {
1779 SMSBackgrounded_ = true;
1781 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1782 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1784 if (&_transcriptTable != NULL)
1785 table = _transcriptTable;
1786 else if (&_transcriptLayer != NULL)
1787 table = _transcriptLayer;
1791 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1792 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1795 [placard insertSubview:background atIndex:0];
1797 [table setBackgroundColor:[UIColor clearColor]];
1798 [placard insertSubview:background belowSubview:table];
1804 // %hook _UIImageWithName() {{{
1805 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1807 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1814 if (_UIPackedImageTableGetIdentifierForName != NULL)
1815 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1816 else if (_UISharedImageNameGetIdentifier != NULL) {
1817 identifier = _UISharedImageNameGetIdentifier(name);
1818 packed = identifier != -1;
1825 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1828 return __UIImageWithName(name);
1830 NSNumber *key([NSNumber numberWithInt:identifier]);
1831 UIImage *image([UIImages_ objectForKey:key]);
1833 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1834 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1835 image = $getImage$(path);
1836 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1840 image = __UIImageWithName(name);
1843 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1844 if (![Manager_ fileExistsAtPath:path])
1845 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1852 // %hook _UIImageWithNameInDomain() {{{
1853 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1854 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1855 UIImage *image([PathImages_ objectForKey:key]);
1857 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1859 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1860 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1861 image = $getImage$(path);
1862 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1863 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1867 // %hook GSFontCreateWithName() {{{
1868 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1870 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1871 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1872 name = [font UTF8String];
1873 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1874 // size *= [scale floatValue];
1875 return _GSFontCreateWithName(name, traits, size);
1879 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1880 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1882 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1884 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1886 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1887 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1889 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1892 NSString *path = [NSString stringWithUTF8String:a1];
1893 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1894 NSString *file = [path substringFromIndex:31];
1895 for (NSString *theme in Themes_) {
1896 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1897 if ([Manager_ fileExistsAtPath:path]) {
1898 strcpy(a1, [path UTF8String]);
1907 static void ChangeWallpaper(
1908 CFNotificationCenterRef center,
1912 CFDictionaryRef info
1915 NSLog(@"WB:Debug:ChangeWallpaper!");
1918 if (WallpaperFile_ != nil) {
1919 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1921 image = [image autorelease];
1924 if (WallpaperImage_ != nil)
1925 [WallpaperImage_ setImage:image];
1926 if (WallpaperPage_ != nil)
1927 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1931 #define WBRename(name, sel, imp) \
1932 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
1934 template <typename Type_>
1935 static void msset(Type_ &function, MSImageRef image, const char *name) {
1936 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1939 template <typename Type_>
1940 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1941 struct nlist &name(nl[index]);
1942 uintptr_t value(name.n_value);
1943 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1944 value |= 0x00000001;
1945 function = reinterpret_cast<Type_>(value);
1948 template <typename Type_>
1949 static void dlset(Type_ &function, const char *name) {
1950 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1953 // %hook CGImageReadCreateWithFile() {{{
1954 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1956 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1957 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1958 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1964 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
1965 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1966 if (style == nil || [style length] == 0)
1967 style = @"font-family: Helvetica; font-size: 12px";
1968 //NSLog(@"XXX:draw(%@)", [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
1969 return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
1972 static void NSString$drawInRect$withStyle$(NSString *self, SEL _cmd, CGRect rect, NSString *style) {
1973 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1974 if (style == nil || [style length] == 0)
1975 style = @"font-family: Helvetica; font-size: 12px";
1976 return [[WBMarkup sharedMarkup] drawString:self inRect:rect withStyle:style];
1979 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
1980 if (style == nil || [style length] == 0)
1981 style = @"font-family: Helvetica; font-size: 12px";
1982 //NSLog(@"XXX:size(%@)", [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
1983 return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width];
1986 static void SBInitialize() {
1988 WBRename(SBApplication, pathForIcon, pathForIcon);
1989 WBRename(SBApplicationIcon, icon, icon);
1990 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1993 WBRename(SBBookmarkIcon, icon, icon);
1994 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1995 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1996 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1997 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
1999 WBRename(SBWidgetApplicationIcon, icon, icon);
2001 WBRename(SBDockIconListView, setFrame:, setFrame$);
2002 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
2004 if (kCFCoreFoundationVersionNumber < 600 || SummerBoard_)
2005 WBRename(SBIconLabel, drawRect:, drawRect$);
2007 WBRename(SBIconLabel, buildLabelImage, buildLabelImage);
2009 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
2010 WBRename(SBIconLabel, setInDock:, setInDock$);
2012 WBRename(SBIconList, setFrame:, setFrame$);
2014 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
2015 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
2016 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
2017 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
2019 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
2020 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
2021 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
2023 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
2025 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
2026 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
2027 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
2028 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
2029 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
2030 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
2031 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
2032 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
2033 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
2036 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
2040 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2042 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
2043 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
2045 Manager_ = [[NSFileManager defaultManager] retain];
2046 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
2048 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
2050 // Load Settings.plist {{{
2051 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
2052 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
2053 SummerBoard_ = [value boolValue];
2055 SummerBoard_ = true;
2057 if (NSNumber *value = [settings objectForKey:@"Debug"])
2058 Debug_ = [value boolValue];
2059 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
2060 UIDebug_ = [value boolValue];
2062 NSArray *themes([settings objectForKey:@"Themes"]);
2064 if (NSString *theme = [settings objectForKey:@"Theme"])
2065 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
2067 [NSNumber numberWithBool:true], @"Active",
2071 for (NSDictionary *theme in themes) {
2072 NSNumber *active([theme objectForKey:@"Active"]);
2073 if (![active boolValue])
2076 NSString *name([theme objectForKey:@"Name"]);
2080 NSString *theme(nil);
2082 #define testForTheme(format...) \
2083 if (theme == nil) { \
2084 NSString *path = [NSString stringWithFormat:format]; \
2085 if ([Manager_ fileExistsAtPath:path]) { \
2086 [Themes_ addObject:path]; \
2091 testForTheme(@"/Library/Themes/%@.theme", name)
2092 testForTheme(@"/Library/Themes/%@", name)
2093 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
2098 // Merge Info.plist {{{
2099 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2101 for (NSString *theme in Themes_)
2102 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
2103 for (NSString *key in [info allKeys])
2104 if ([Info_ objectForKey:key] == nil)
2105 [Info_ setObject:[info objectForKey:key] forKey:key];
2109 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
2110 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
2111 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
2114 // GraphicsServices {{{
2116 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
2120 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
2121 void *(*CGImageReadCreateWithFile)(NSString *, int);
2122 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
2123 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
2128 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
2129 Papered_ = $getTheme$(Wallpapers_) != nil;
2130 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
2132 CFNotificationCenterAddObserver(
2133 CFNotificationCenterGetDarwinNotifyCenter(),
2134 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
2137 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
2138 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
2139 if (MediaPlayer != nil)
2142 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
2143 $MPVideoView = objc_getClass("MPVideoView");
2150 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
2151 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
2152 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v28@0:4{CGRect={CGSize=ff}{CGSize=ff}}8@24");
2153 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
2156 memset(nl, 0, sizeof(nl));
2157 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
2158 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
2159 nl[2].n_un.n_name = (char *) "__UIKitBundle";
2160 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
2161 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
2164 nlset(_UIApplicationImageWithName, nl, 0);
2165 nlset(_UIImageWithNameInDomain, nl, 1);
2166 nlset(_UIKitBundle, nl, 2);
2167 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
2168 nlset(_UISharedImageNameGetIdentifier, nl, 4);
2170 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
2171 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
2172 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
2176 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
2177 NSError *error(nil);
2178 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
2179 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
2181 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);