1 /* WinterBoard - Theme Manager for the iPhone
2 * Copyright (C) 2008-2011 Jay Freeman (saurik)
6 * Redistribution and use in source and binary
7 * forms, with or without modification, are permitted
8 * provided that the following conditions are met:
10 * 1. Redistributions of source code must retain the
11 * above copyright notice, this list of conditions
12 * and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the
14 * above copyright notice, this list of conditions
15 * and the following disclaimer in the documentation
16 * and/or other materials provided with the
18 * 3. The name of the author may not be used to endorse
19 * or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
33 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
43 #define _trace() do { \
44 struct timeval _ctv; \
45 gettimeofday(&_ctv, NULL); \
50 NSLog(@"%lu.%.6u[%f]:WB:_trace()@%s:%u[%s]\n", \
51 _ctv.tv_sec, _ctv.tv_usec, \
52 (_ctv.tv_sec - _ltv.tv_sec) + (_ctv.tv_usec - _ltv.tv_usec) / 1000000.0, \
53 __FILE__, __LINE__, __FUNCTION__\
60 #import <CoreFoundation/CoreFoundation.h>
61 #import <Foundation/Foundation.h>
62 #import <CoreGraphics/CoreGraphics.h>
63 #import <ImageIO/CGImageSource.h>
65 #import <Celestial/AVController.h>
66 #import <Celestial/AVItem.h>
67 #import <Celestial/AVQueue.h>
69 #include <substrate.h>
71 #import <UIKit/UIKit.h>
73 #import <SpringBoard/SBApplication.h>
74 #import <SpringBoard/SBApplicationIcon.h>
75 #import <SpringBoard/SBAppWindow.h>
76 #import <SpringBoard/SBAwayView.h>
77 #import <SpringBoard/SBBookmarkIcon.h>
78 #import <SpringBoard/SBButtonBar.h>
79 #import <SpringBoard/SBCalendarIconContentsView.h>
80 #import <SpringBoard/SBIconController.h>
81 #import <SpringBoard/SBIconLabel.h>
82 #import <SpringBoard/SBIconList.h>
83 #import <SpringBoard/SBIconModel.h>
84 #import <SpringBoard/SBImageCache.h>
85 // XXX: #import <SpringBoard/SBSearchView.h>
86 #import <SpringBoard/SBSearchTableViewCell.h>
87 #import <SpringBoard/SBStatusBarContentsView.h>
88 #import <SpringBoard/SBStatusBarController.h>
89 #import <SpringBoard/SBStatusBarOperatorNameView.h>
90 #import <SpringBoard/SBStatusBarTimeView.h>
91 #import <SpringBoard/SBUIController.h>
92 #import <SpringBoard/SBWidgetApplicationIcon.h>
94 #import <MobileSMS/mSMSMessageTranscriptController.h>
96 #import <MediaPlayer/MPMoviePlayerController.h>
97 #import <MediaPlayer/MPVideoView.h>
98 #import <MediaPlayer/MPVideoView-PlaybackControl.h>
100 #import <CoreGraphics/CGGeometry.h>
102 #import <ChatKit/CKMessageCell.h>
104 #include <sys/sysctl.h>
106 #include "WBMarkup.h"
108 extern "C" void __clear_cache (char *beg, char *end);
110 static void (*$objc_setAssociatedObject)(id object, void *key, id value, objc_AssociationPolicy policy);
111 static id (*$objc_getAssociatedObject)(id object, void *key);
112 static void (*$objc_removeAssociatedObjects)(id object);
114 @protocol WinterBoard
118 Class $MPMoviePlayerController;
121 MSClassHook(NSBundle)
122 MSClassHook(NSString)
125 MSMetaClassHook(UIImage)
126 MSClassHook(UINavigationBar)
127 MSClassHook(UIToolbar)
128 MSClassHook(UIStatusBarTimeItemView)
129 MSClassHook(UIWebDocumentView)
131 MSClassHook(CKBalloonView)
132 MSClassHook(CKMessageCell)
133 MSClassHook(CKTimestampView)
134 MSClassHook(CKTranscriptCell)
135 MSClassHook(CKTranscriptController)
136 MSClassHook(CKTranscriptHeaderView)
137 MSClassHook(CKTranscriptTableView)
139 MSClassHook(SBApplication)
140 MSClassHook(SBApplicationIcon)
141 MSClassHook(SBAwayView)
142 MSClassHook(SBBookmarkIcon)
143 MSClassHook(SBButtonBar)
144 MSClassHook(SBCalendarApplicationIcon)
145 MSClassHook(SBCalendarIconContentsView)
146 MSClassHook(SBDockIconListView)
148 MSClassHook(SBIconBadge)
149 MSClassHook(SBIconBadgeFactory)
150 MSClassHook(SBIconContentView)
151 MSClassHook(SBIconController)
152 MSClassHook(SBIconLabel)
153 MSClassHook(SBIconLabelImage)
154 MSMetaClassHook(SBIconLabelImage)
155 MSClassHook(SBIconLabelImageParameters)
156 MSClassHook(SBIconList)
157 MSClassHook(SBIconModel)
158 MSClassHook(SBIconView)
159 MSMetaClassHook(SBIconView)
160 //MSClassHook(SBImageCache)
161 MSClassHook(SBSearchView)
162 MSClassHook(SBSearchTableViewCell)
163 MSClassHook(SBSlidingAlertDisplay)
164 MSClassHook(SBStatusBarContentsView)
165 MSClassHook(SBStatusBarController)
166 MSClassHook(SBStatusBarOperatorNameView)
167 MSClassHook(SBStatusBarTimeView)
168 MSClassHook(SBUIController)
169 MSClassHook(SBWallpaperView)
170 MSClassHook(SBWidgetApplicationIcon)
172 extern "C" void WKSetCurrentGraphicsContext(CGContextRef);
174 static struct MSFixClass { MSFixClass() {
175 $UIWebDocumentView = objc_getClass("UIWebBrowserView") ?: $UIWebDocumentView;
176 $SBIcon = objc_getClass("SBIconView") ?: $SBIcon;
178 if ($SBIconList == nil)
179 $SBIconList = objc_getClass("SBIconListView");
180 if ($CKTranscriptController == nil)
181 $CKTranscriptController = objc_getClass("mSMSMessageTranscriptController");
185 static bool Four_($SBDockIconListView != nil);
187 @interface NSDictionary (WinterBoard)
188 - (UIColor *) wb$colorForKey:(NSString *)key;
189 - (BOOL) wb$boolForKey:(NSString *)key;
192 @implementation NSDictionary (WinterBoard)
194 - (UIColor *) wb$colorForKey:(NSString *)key {
195 NSString *value = [self objectForKey:key];
202 - (BOOL) wb$boolForKey:(NSString *)key {
203 if (NSString *value = [self objectForKey:key])
204 return [value boolValue];
210 static BOOL (*_GSFontGetUseLegacyFontMetrics)();
211 #define $GSFontGetUseLegacyFontMetrics() \
212 (_GSFontGetUseLegacyFontMetrics == NULL ? YES : _GSFontGetUseLegacyFontMetrics())
214 static bool Debug_ = false;
215 static bool UIDebug_ = false;
216 static bool Engineer_ = false;
217 static bool SummerBoard_ = false;
218 static bool SpringBoard_;
220 static UIImage *(*_UIApplicationImageWithName)(NSString *name);
221 static UIImage *(*_UIImageWithNameInDomain)(NSString *name, NSString *domain);
222 static NSBundle *(*_UIKitBundle)();
223 static bool (*_UIPackedImageTableGetIdentifierForName)(NSString *, int *);
224 static int (*_UISharedImageNameGetIdentifier)(NSString *);
226 static NSMutableDictionary *UIImages_ = [[NSMutableDictionary alloc] initWithCapacity:32];
227 static NSMutableDictionary *PathImages_ = [[NSMutableDictionary alloc] initWithCapacity:16];
228 static NSMutableDictionary *Cache_ = [[NSMutableDictionary alloc] initWithCapacity:64];
229 static NSMutableDictionary *Strings_ = [[NSMutableDictionary alloc] initWithCapacity:0];
230 static NSMutableDictionary *Bundles_ = [[NSMutableDictionary alloc] initWithCapacity:2];
232 static NSFileManager *Manager_;
233 static NSMutableArray *Themes_;
235 static NSDictionary *English_;
236 static NSMutableDictionary *Info_;
239 static NSMutableDictionary *Themed_ = [[NSMutableDictionary alloc] initWithCapacity:128];
241 static unsigned Scale_ = 0;
243 static unsigned $getScale$(NSString *path) {
244 NSString *name(path);
246 #define StripName(strip) \
247 if ([name hasSuffix:@ strip]) \
248 name = [name substringWithRange:NSMakeRange(0, [name length] - sizeof(strip) - 1)];
252 StripName("~iphone");
255 return [name hasSuffix:@"@2x"] ? 2 : 1;
258 static NSArray *$useScale$(NSArray *files, bool use = true) {
259 if (use && Scale_ == 0) {
260 UIScreen *screen([UIScreen mainScreen]);
261 if ([screen respondsToSelector:@selector(scale)])
262 Scale_ = [screen scale];
270 NSString *idiom(IsWild_ ? @"ipad" : @"iphone");
272 NSMutableArray *scaled([NSMutableArray arrayWithCapacity:([files count] * 4)]);
274 for (NSString *file in files) {
275 NSString *base([file stringByDeletingPathExtension]);
276 NSString *extension([file pathExtension]);
280 [scaled addObject:[NSString stringWithFormat:@"%@@2x~%@.%@", base, idiom, extension]];
281 [scaled addObject:[NSString stringWithFormat:@"%@@2x.%@", base, extension]];
284 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
286 // if (!IsWild_) <- support old themes
287 [scaled addObject:file];
288 } else if ([base hasSuffix: @"@2x"]) {
289 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
290 [scaled addObject:file];
292 // XXX: this actually can't be used, as the person loading the file doesn't realize that the @2x changed
293 /*NSString *rest([base substringWithRange:NSMakeRange(0, [base length] - 3)]);
294 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", rest, idiom, extension]];
295 [scaled addObject:[rest stringByAppendingPathExtension:extension]];*/
297 // XXX: this code isn't really complete
299 [scaled addObject:file];
301 if ([base hasSuffix:[NSString stringWithFormat:@"~%@", idiom]])
302 [scaled addObject:[[base substringWithRange:NSMakeRange(0, [base length] - 1 - [idiom length])] stringByAppendingPathExtension:extension]];
309 static NSString *$getTheme$(NSArray *files, NSArray *themes = Themes_) {
310 // XXX: this is not reasonable; OMG
313 @synchronized (Themed_) {
314 if (NSString *path = [Themed_ objectForKey:key])
315 return reinterpret_cast<id>(path) == [NSNull null] ? nil : path;
319 NSLog(@"WB:Debug: %@", [files description]);
323 for (NSString *theme in Themes_)
324 for (NSString *file in files) {
325 path = [NSString stringWithFormat:@"%@/%@", theme, file];
326 if ([Manager_ fileExistsAtPath:path]) {
327 if ([[Manager_ pathContentOfSymbolicLinkAtPath:path] isEqualToString:@"/"])
336 @synchronized (Themed_) {
337 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:key];
343 // $pathForFile$inBundle$() {{{
344 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool ui) {
345 NSString *identifier = [bundle bundleIdentifier];
346 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
348 if (identifier != nil)
349 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
350 if (NSString *folder = [[bundle bundlePath] lastPathComponent]) {
351 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
352 NSString *base([folder stringByDeletingPathExtension]);
353 if ([base hasSuffix:@"~iphone"])
354 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 7)], [folder pathExtension], file]];
355 if ([base hasSuffix:@"~ipad"])
356 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 5)], [folder pathExtension], file]];
359 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
361 #define remapResourceName(oldname, newname) \
362 else if ([file isEqualToString:(oldname)]) \
363 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
365 bool summer(SpringBoard_ && SummerBoard_);
367 if (identifier == nil);
368 else if ([identifier isEqualToString:@"com.apple.chatkit"])
369 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
370 else if ([identifier isEqualToString:@"com.apple.calculator"])
371 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
373 remapResourceName(@"FSO_BG.png", @"StatusBar")
374 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
375 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
377 [names addObject:[NSString stringWithFormat:@"Fallback/%@", file]];
379 if (NSString *path = $getTheme$($useScale$(names, ui)))
386 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
387 NSString *identifier = [self bundleIdentifier];
388 NSString *path = [self path];
389 NSString *folder = [path lastPathComponent];
390 NSString *dname = [self displayName];
391 NSString *didentifier = [self displayIdentifier];
394 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
396 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
398 /* XXX: I might need to keep this for backwards compatibility
399 if (identifier != nil)
400 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
402 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
404 #define testForIcon(Name) \
405 if (NSString *name = Name) \
406 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
408 if (![didentifier isEqualToString:identifier])
409 testForIcon(didentifier);
411 testForIcon(identifier);
414 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
417 if (didentifier != nil) {
418 testForIcon([English_ objectForKey:didentifier]);
420 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
421 if ([parts count] != 1)
422 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
423 testForIcon([english objectForKey:[parts lastObject]]);
426 if (NSString *path = $getTheme$(names))
432 // -[NSBundle wb$bundleWithFile] {{{
433 @interface NSBundle (WinterBoard)
434 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
437 @implementation NSBundle (WinterBoard)
439 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
440 path = [path stringByDeletingLastPathComponent];
441 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
444 NSBundle *bundle([Bundles_ objectForKey:path]);
445 if (reinterpret_cast<id>(bundle) == [NSNull null])
447 else if (bundle == nil) {
448 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
449 bundle = [NSBundle bundleWithPath:path];
451 bundle = [NSBundle wb$bundleWithFile:path];
453 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
454 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
462 // -[NSString wb$themedPath] {{{
463 @interface NSString (WinterBoard)
464 - (NSString *) wb$themedPath;
467 @implementation NSString (WinterBoard)
469 - (NSString *) wb$themedPath {
470 if ([self hasPrefix:@"/Library/Themes/"])
474 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
476 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
477 NSString *file([self stringByResolvingSymlinksInPath]);
478 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
479 if ([file hasPrefix:prefix]) {
480 NSUInteger length([prefix length]);
481 if (length != [file length])
482 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
493 void WBLogRect(const char *tag, struct CGRect rect) {
494 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
497 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
498 CGRect frame([view frame]);
499 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]);
501 for (UIView *child in [view subviews])
502 WBLogHierarchy(child, index++, indent + 1);
505 UIImage *$cacheForImage$(UIImage *image) {
506 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
507 CGRect rect = {CGPointMake(1, 1), [image size]};
508 CGSize size = {rect.size.width + 2, rect.size.height + 2};
510 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
511 CGColorSpaceRelease(space);
513 CGContextDrawImage(context, rect, [image CGImage]);
514 CGImageRef ref(CGBitmapContextCreateImage(context));
515 CGContextRelease(context);
517 UIImage *cache([UIImage imageWithCGImage:ref]);
523 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
524 //if ([name isEqualToString:@"icons"]) return nil;
525 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
528 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
529 NSString *key([icon displayIdentifier]);
531 if (UIImage *image = [icon icon]) {
532 CGSize size = [image size];
533 if (size.width != 59 || size.height != 60) {
534 UIImage *cache($cacheForImage$(image));
535 [Cache_ setObject:cache forKey:key];
540 _SBIconModel$cacheImageForIcon$(self, sel, icon);
543 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
544 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
545 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
547 NSString *key([icon displayIdentifier]);
549 if (UIImage *image = [icon icon]) {
550 CGSize size = [image size];
551 if (size.width != 59 || size.height != 60) {
552 UIImage *cache($cacheForImage$(image));
553 [Cache_ setObject:cache forKey:key];
559 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
560 NSString *key([icon displayIdentifier]);
561 if (UIImage *image = [Cache_ objectForKey:key])
564 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
567 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
569 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
570 NSString *key([icon displayIdentifier]);
571 if (UIImage *image = [Cache_ objectForKey:key])
574 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
577 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
578 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
579 [self setBackgroundColor:[UIColor clearColor]];
580 for (UIView *child in [self subviews])
581 [child setBackgroundColor:[UIColor clearColor]];
585 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
586 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
587 [self setBackgroundColor:[UIColor clearColor]];
591 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
592 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
593 float inset([self edgeInset]);
594 [[UIColor clearColor] set];
595 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
596 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
599 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
600 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
601 if (NSString *path = $pathForIcon$([self application]))
602 return [UIImage imageWithContentsOfFile:path];
603 return _SBApplicationIcon$icon(self, sel);
606 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
608 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
609 if (IsWild_ && false) // XXX: delete this code, it should not be supported
610 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
611 return [UIImage imageWithContentsOfFile:path72];
612 if (NSString *path = $pathForIcon$([self application]))
613 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
615 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
616 width = [$SBIcon defaultIconImageSize].width;
619 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
622 return _SBApplicationIcon$generateIconImage$(self, sel, type);
625 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
627 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
628 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
629 return [UIImage imageWithContentsOfFile:path];
630 return _SBWidgetApplicationIcon$icon(self, sel);
633 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
635 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
636 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
637 return [UIImage imageWithContentsOfFile:path];
638 return _SBBookmarkIcon$icon(self, sel);
641 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
642 if (NSString *path = $pathForIcon$(self))
644 return _SBApplication$pathForIcon(self, sel);
647 static UIImage *CachedImageAtPath(NSString *path) {
648 path = [path stringByResolvingSymlinksInPath];
649 UIImage *image = [PathImages_ objectForKey:path];
651 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
652 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
654 image = [image autorelease];
655 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
659 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
660 NSBundle *bundle = [NSBundle mainBundle];
662 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
663 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
664 return CachedImageAtPath(path);
665 return __UIApplicationImageWithName(name);
668 #define WBDelegate(delegate) \
669 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
671 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
672 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
674 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
678 - (void) forwardInvocation:(NSInvocation*)inv { \
679 SEL sel = [inv selector]; \
680 if ([delegate respondsToSelector:sel]) \
681 [inv invokeWithTarget:delegate]; \
683 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
686 // %hook -[NSBundle pathForResource:ofType:] {{{
687 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
688 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
690 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
691 if (NSString *path = $pathForFile$inBundle$(file, self, false))
693 return MSOldCall(resource, type);
697 static void $drawLabel$(NSString *label, CGRect rect, NSString *style, NSString *custom) {
698 bool ellipsis(false);
699 float max = rect.size.width - 11, width;
701 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
704 size_t length([label length]);
705 float spacing((width - max) / (length - 1));
707 if (spacing > 1.25) {
709 label = [label substringToIndex:(length - 1)];
713 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
717 label = [label stringByAppendingString:@"..."];
720 style = [style stringByAppendingString:custom];
722 CGSize size = [label sizeWithStyle:style forWidth:rect.size.width];
723 [label drawAtPoint:CGPointMake((rect.size.width - size.width) / 2 + rect.origin.x, rect.origin.y) withStyle:style];
726 static struct WBStringDrawingState {
727 WBStringDrawingState *next_;
731 } *stringDrawingState_;
733 extern "C" CGColorSpaceRef CGContextGetFillColorSpace(CGContextRef);
734 extern "C" void CGContextGetFillColor(CGContextRef, CGFloat[]);
736 static NSString *WBColorMarkup() {
737 CGContextRef context(UIGraphicsGetCurrentContext());
738 //NSLog(@"XXX:1:%p", context);
742 CGColorSpaceRef space(CGContextGetFillColorSpace(context));
743 //NSLog(@"XXX:2:%p", space);
747 size_t number(CGColorSpaceGetNumberOfComponents(space));
748 //NSLog(@"XXX:3:%u", number);
752 CGFloat components[number + 1];
753 CGContextGetFillColor(context, components);
776 return [NSString stringWithFormat:@"color: rgba(%g, %g, %g, %g)", r * 255, g * 255, b * 255, a];
779 MSInstanceMessageHook6(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode,letterSpacing,includeEmoji, CGPoint, point, float, width, UIFont *, font, UILineBreakMode, mode, float, spacing, BOOL, emoji) {
780 //NSLog(@"XXX: @\"%@\" %g", self, spacing);
782 WBStringDrawingState *state(stringDrawingState_);
784 return MSOldCall(point, width, font, mode, spacing, emoji);
786 if (--state->count_ == 0)
787 stringDrawingState_ = state->next_;
788 if (state->info_ == nil)
789 return MSOldCall(point, width, font, mode, spacing, emoji);
791 NSString *info([Info_ objectForKey:state->info_]);
793 return MSOldCall(point, width, font, mode, spacing, emoji);
795 NSString *base(state->base_ ?: @"");
796 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
797 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
801 extern "C" NSString *NSStringFromCGRect(CGRect rect);
803 MSInstanceMessageHook7(CGSize, NSString, _drawInRect,withFont,lineBreakMode,alignment,lineSpacing,includeEmoji,truncationRect, CGRect, rect, UIFont *, font, UILineBreakMode, mode, UITextAlignment, alignment, float, spacing, BOOL, emoji, CGRect, truncation) {
804 //NSLog(@"XXX: &\"%@\" %@ \"%@\" %u %u %g %u %@", self, NSStringFromCGRect(rect), font, mode, alignment, spacing, emoji, NSStringFromCGRect(truncation));
806 WBStringDrawingState *state(stringDrawingState_);
808 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
810 if (--state->count_ == 0)
811 stringDrawingState_ = state->next_;
812 if (state->info_ == nil)
813 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
815 NSString *info([Info_ objectForKey:state->info_]);
817 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
822 case UITextAlignmentLeft:
825 case UITextAlignmentCenter:
826 textAlign = @"center";
828 case UITextAlignmentRight:
829 textAlign = @"right";
833 NSString *base(state->base_ ?: @"");
834 NSString *extra([NSString stringWithFormat:@"text-align: %@", textAlign]);
837 $drawLabel$(self, rect, [NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], WBColorMarkup(), base], info);
839 [self drawInRect:rect withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
844 MSInstanceMessageHook4(CGSize, NSString, sizeWithFont,forWidth,lineBreakMode,letterSpacing, UIFont *, font, float, width, UILineBreakMode, mode, float, spacing) {
845 //NSLog(@"XXX: #\"%@\" \"%@\" %g %u %g", self, font, width, mode, spacing);
847 WBStringDrawingState *state(stringDrawingState_);
849 return MSOldCall(font, width, mode, spacing);
851 if (--state->count_ == 0)
852 stringDrawingState_ = state->next_;
853 if (state->info_ == nil)
854 return MSOldCall(font, width, mode, spacing);
856 NSString *info([Info_ objectForKey:state->info_]);
858 return MSOldCall(font, width, mode, spacing);
860 NSString *base(state->base_ ?: @"");
861 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
862 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info] forWidth:width];
865 MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) {
866 //NSLog(@"XXX: ?\"%@\"", self);
868 WBStringDrawingState *state(stringDrawingState_);
870 return MSOldCall(font);
872 if (--state->count_ == 0)
873 stringDrawingState_ = state->next_;
874 if (state->info_ == nil)
875 return MSOldCall(font);
877 NSString *info([Info_ objectForKey:state->info_]);
879 return MSOldCall(font);
881 NSString *base(state->base_ ?: @"");
882 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), base, info] forWidth:65535];
885 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
886 WBStringDrawingState badgeState = {NULL, -1, @""
889 stringDrawingState_ = &badgeState;
891 UIImage *image(MSOldCall(text));
893 stringDrawingState_ = NULL;
897 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
898 WBStringDrawingState dayState = {NULL, 2, @""
899 // XXX: this is only correct on an iPod dock
900 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
901 , @"CalendarIconDayStyle"};
903 WBStringDrawingState sizeState = {&dayState, 7, nil, nil};
905 WBStringDrawingState dateState = {&sizeState, 2, @""
906 , @"CalendarIconDateStyle"};
908 stringDrawingState_ = &dateState;
910 UIImage *image(MSOldCall(type));
912 stringDrawingState_ = NULL;
916 MSInstanceMessageHook1(UIImage *, UIStatusBarTimeItemView, contentsImageForStyle, int, style) {
917 WBStringDrawingState timeState = {NULL, 0, @""
920 stringDrawingState_ = &timeState;
922 UIImage *image(MSOldCall(style));
924 stringDrawingState_ = NULL;
928 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
929 NSBundle *bundle([NSBundle mainBundle]);
931 CFLocaleRef locale(CFLocaleCopyCurrent());
932 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
935 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
937 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
938 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
939 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
940 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
944 CFRelease(formatter);
946 NSString *datestyle([@""
947 "font-family: Helvetica; "
948 "font-weight: bold; "
951 "" stringByAppendingString:(IsWild_
952 ? @"font-size: 54px; "
953 : @"font-size: 39px; "
956 NSString *daystyle([@""
957 "font-family: Helvetica; "
958 "font-weight: bold; "
960 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
961 "" stringByAppendingString:(IsWild_
962 ? @"font-size: 11px; "
963 : @"font-size: 9px; "
966 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
967 datestyle = [datestyle stringByAppendingString:style];
968 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
969 daystyle = [daystyle stringByAppendingString:style];
971 float width([self bounds].size.width);
973 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
974 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
976 unsigned base0(IsWild_ ? 89 : 70);
977 if ($GSFontGetUseLegacyFontMetrics())
979 unsigned base1(IsWild_ ? 18 : 16);
986 [(NSString *)date drawAtPoint:CGPointMake(
987 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
988 ) withStyle:datestyle];
990 [(NSString *)day drawAtPoint:CGPointMake(
991 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
992 ) withStyle:daystyle];
998 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
999 void $setBarStyle$_(NSString *name, int &style) {
1001 NSLog(@"WB:Debug:%@Style:%d", name, style);
1002 NSNumber *number = nil;
1004 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
1006 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
1007 if (number != nil) {
1008 style = [number intValue];
1010 NSLog(@"WB:Debug:%@Style=%d", name, style);
1014 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
1015 $setBarStyle$_(@"Toolbar", style);
1016 return MSOldCall(style);
1019 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
1020 $setBarStyle$_(@"NavigationBar", style);
1021 return MSOldCall(style);
1025 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
1026 [[self superview] setBackgroundColor:[UIColor clearColor]];
1027 _SBButtonBar$didMoveToSuperview(self, sel);
1030 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
1031 [[self superview] setBackgroundColor:[UIColor clearColor]];
1032 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
1035 static NSArray *Wallpapers_;
1036 static bool Papered_;
1037 static bool Docked_;
1038 static bool SMSBackgrounded_;
1039 static NSString *WallpaperFile_;
1040 static UIImageView *WallpaperImage_;
1041 static UIWebDocumentView *WallpaperPage_;
1042 static NSURL *WallpaperURL_;
1044 #define _release(object) \
1045 do if (object != nil) { \
1050 static UIImage *$getImage$(NSString *path) {
1051 UIImage *image([UIImage imageWithContentsOfFile:path]);
1053 unsigned scale($getScale$(path));
1054 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
1055 [image setScale:scale];
1060 static UIImage *$getDefaultDesktopImage$() {
1061 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
1062 return $getImage$(path);
1066 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
1067 return $getDefaultDesktopImage$() ?: MSOldCall();
1070 MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
1071 return $getDefaultDesktopImage$() ?: MSOldCall();
1074 MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
1075 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
1076 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
1077 if (UIImage *image = $getDefaultDesktopImage$()) {
1078 [self setImage:image];
1088 // %hook -[SBUIController init] {{{
1089 MSInstanceMessageHook0(id, SBUIController, init) {
1094 NSString *paper($getTheme$(Wallpapers_));
1096 paper = [paper stringByDeletingLastPathComponent];
1100 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
1101 char *machine = new char[size];
1103 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
1104 perror("sysctlbyname(\"hw.machine\", ?)");
1109 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
1113 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
1116 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
1117 if (&_wallpaperView != NULL) {
1118 [_wallpaperView removeFromSuperview];
1119 [_wallpaperView release];
1120 _wallpaperView = nil;
1124 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
1125 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
1128 if (&_contentLayer != NULL)
1129 player = &_contentLayer;
1130 else if (&_contentView != NULL)
1131 player = &_contentView;
1134 UIView *layer(player == NULL ? nil : *player);
1136 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
1137 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
1138 [window setContentView:content];
1140 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
1141 [window setBackgroundColor:[_window backgroundColor]];
1142 [_window setBackgroundColor:[UIColor clearColor]];
1144 [window setLevel:-1000];
1145 [window setHidden:NO];
1147 /*if (player != NULL)
1148 *player = content;*/
1150 [content setBackgroundColor:[layer backgroundColor]];
1151 [layer setBackgroundColor:[UIColor clearColor]];
1154 if (!SummerBoard_ || !IsWild_)
1157 CGRect bounds([content bounds]);
1158 bounds.origin.y = -30;
1159 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
1160 [content addSubview:indirect];
1161 [indirect zoomToScale:2.4];
1164 _release(WallpaperFile_);
1165 _release(WallpaperImage_);
1166 _release(WallpaperPage_);
1167 _release(WallpaperURL_);
1170 NSArray *themes([NSArray arrayWithObject:paper]);
1172 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1176 static AVController *controller_(nil);
1177 if (controller_ == nil) {
1178 AVQueue *queue([AVQueue avQueue]);
1179 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1182 AVQueue *queue([controller_ queue]);
1184 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1185 [controller_ setLayer:[video _layer]];
1187 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1188 [queue appendItem:item error:&error];
1190 [controller_ play:&error];
1191 #elif UseMPMoviePlayerController
1192 NSURL *url([NSURL fileURLWithPath:path]);
1193 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1194 controller.movieControlMode = MPMovieControlModeHidden;
1197 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1198 [video setMovieWithPath:path];
1199 [video setRepeatMode:1];
1200 [video setRepeatGap:-1];
1201 [video playFromBeginning];;
1204 [indirect addSubview:video];
1207 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1208 if (UIImage *image = $getImage$(path)) {
1209 WallpaperFile_ = [path retain];
1210 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1211 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1212 [WallpaperImage_ setAlpha:[number floatValue]];
1213 [indirect addSubview:WallpaperImage_];
1217 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1218 CGRect bounds = [indirect bounds];
1220 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1221 [view setAutoresizes:true];
1223 WallpaperPage_ = [view retain];
1224 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1226 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1228 [view setBackgroundColor:[UIColor clearColor]];
1229 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1230 [view setDrawsBackground:NO];
1231 [[view webView] setDrawsBackground:NO];
1233 [indirect addSubview:view];
1237 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1238 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1239 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1240 if ([Manager_ fileExistsAtPath:html]) {
1241 CGRect bounds = [indirect bounds];
1243 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1244 [view setAutoresizes:true];
1246 NSURL *url = [NSURL fileURLWithPath:html];
1247 [view loadRequest:[NSURLRequest requestWithURL:url]];
1249 [view setBackgroundColor:[UIColor clearColor]];
1250 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1251 [view setDrawsBackground:NO];
1252 [[view webView] setDrawsBackground:NO];
1254 [indirect addSubview:view];
1262 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1263 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1264 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1266 if (path != nil && _backgroundView != nil)
1269 _SBAwayView$updateDesktopImage$(self, sel, image);
1272 CGRect bounds = [self bounds];
1274 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1275 [view setAutoresizes:true];
1277 if (WallpaperPage_ != nil)
1278 [WallpaperPage_ release];
1279 WallpaperPage_ = [view retain];
1281 if (WallpaperURL_ != nil)
1282 [WallpaperURL_ release];
1283 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1285 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1287 [[view webView] setDrawsBackground:false];
1288 [view setBackgroundColor:[UIColor clearColor]];
1290 [self insertSubview:view aboveSubview:_backgroundView];
1294 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1295 extern "C" CGColorRef CGGStateGetFillColor(void *);
1296 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1297 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1299 /* WBTimeLabel {{{ */
1300 @interface WBTimeLabel : NSProxy {
1302 _transient SBStatusBarTimeView *view_;
1305 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1309 @implementation WBTimeLabel
1316 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1317 time_ = [time retain];
1322 - (NSString *) description {
1328 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1329 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1330 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1332 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1333 "font-family: Helvetica; "
1334 "font-weight: bold; "
1337 "%@", _mode ? @"white" : @"black", custom]];
1342 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1347 /* WBBadgeLabel {{{ */
1348 @interface WBBadgeLabel : NSProxy {
1352 - (id) initWithBadge:(NSString *)badge;
1353 - (NSString *) description;
1357 @implementation WBBadgeLabel
1364 - (id) initWithBadge:(NSString *)badge {
1365 badge_ = [badge retain];
1369 - (NSString *) description {
1370 return [badge_ description];
1375 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1376 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1377 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1378 "font-family: Helvetica; "
1379 "font-weight: bold; "
1387 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1394 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1395 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1396 alpha = [number floatValue];
1397 return MSOldCall(alpha);
1400 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1401 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1402 alpha = [number floatValue];
1403 return MSOldCall(alpha);
1406 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1407 if ((self = MSOldCall()) != nil) {
1408 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1409 // XXX: note: this is overridden above, which is silly
1410 float alpha([number floatValue]);
1411 if ([self respondsToSelector:@selector(setIconImageAlpha:)])
1412 [self setIconImageAlpha:alpha];
1413 if ([self respondsToSelector:@selector(setIconLabelAlpha:)])
1414 [self setIconLabelAlpha:alpha];
1415 if ([self respondsToSelector:@selector(setAlpha:)])
1416 [self setAlpha:alpha];
1421 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1422 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1423 alpha = [number floatValue];
1424 return MSOldCall(alpha);
1428 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1429 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1430 id &_badge(MSHookIvar<id>(self, "_badge"));
1432 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1437 void SBStatusBarController$setStatusBarMode(int &mode) {
1439 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1440 if (mode < 100) // 104:hidden 105:glowing
1441 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1442 mode = [number intValue];
1445 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1446 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1447 SBStatusBarController$setStatusBarMode(mode);
1448 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1451 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1452 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1453 SBStatusBarController$setStatusBarMode(mode);
1454 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1457 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) {
1458 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1459 SBStatusBarController$setStatusBarMode(mode);
1460 //NSLog(@"mode=%u", mode);
1461 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1464 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1465 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1466 mode = [number intValue];
1467 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1470 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1471 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1473 NSLog(@"operatorNameStyle= %@", style);
1474 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1475 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1479 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1481 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1482 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1485 // XXX: replace this with [SBStatusBarTimeView tile]
1486 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1487 id &_time(MSHookIvar<id>(self, "_time"));
1488 if (_time != nil && [_time class] != [WBTimeLabel class])
1489 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1490 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1493 @interface UIView (WinterBoard)
1494 - (bool) wb$isWBImageView;
1495 - (void) wb$logHierarchy;
1496 - (void) wb$setBackgroundColor:(UIColor *)color;
1499 @implementation UIView (WinterBoard)
1501 - (bool) wb$isWBImageView {
1505 - (void) wb$logHierarchy {
1506 WBLogHierarchy(self);
1509 - (void) wb$setBackgroundColor:(UIColor *)color {
1510 [self setBackgroundColor:color];
1511 for (UIView *child in [self subviews])
1512 [child wb$setBackgroundColor:color];
1517 @interface WBImageView : UIImageView {
1520 - (bool) wb$isWBImageView;
1521 - (void) wb$updateFrame;
1524 @implementation WBImageView
1526 - (bool) wb$isWBImageView {
1530 - (void) wb$updateFrame {
1531 CGRect frame([self frame]);
1534 for (UIView *view(self); ; ) {
1535 view = [view superview];
1538 frame.origin.y -= [view frame].origin.y;
1541 [self setFrame:frame];
1546 static void SBIconList$updateFrames$(SBIconList *self) {
1547 NSArray *subviews([self subviews]);
1548 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1549 if (view != nil && [view wb$isWBImageView])
1550 [view wb$updateFrame];
1553 MSHook(void, SBIconList$didMoveToSuperview, SBIconList *self, SEL sel) {
1554 SBIconList$updateFrames$(self);
1555 _SBIconList$didMoveToSuperview(self, sel);
1558 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1559 SBIconList$updateFrames$(self);
1560 _SBIconList$setFrame$(self, sel, frame);
1563 static void $addPerPageView$(unsigned i, UIView *list) {
1564 NSString *path($getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]]));
1568 NSArray *subviews([list subviews]);
1570 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1571 if (view == nil || ![view wb$isWBImageView]) {
1572 view = [[[WBImageView alloc] init] autorelease];
1573 [list insertSubview:view atIndex:0];
1576 UIImage *image([UIImage imageWithContentsOfFile:path]);
1578 CGRect frame([view frame]);
1579 frame.size = [image size];
1580 [view setFrame:frame];
1582 [view setImage:image];
1583 [view wb$updateFrame];
1586 static void $addPerPageViews$(NSArray *lists) {
1587 for (unsigned i(0), e([lists count]); i != e; ++i)
1588 $addPerPageView$(i, [lists objectAtIndex:i]);
1591 MSInstanceMessageHook0(void, SBIconController, updateNumberOfRootIconLists) {
1592 NSArray *&_rootIconLists(MSHookIvar<NSArray *>(self, "_rootIconLists"));
1593 $addPerPageViews$(_rootIconLists);
1597 MSInstanceMessageHook0(void, SBIconContentView, layoutSubviews) {
1600 if (SBIconController *controller = [$SBIconController sharedInstance]) {
1601 UIView *&_dockContainerView(MSHookIvar<UIView *>(controller, "_dockContainerView"));
1602 if (&_dockContainerView != NULL)
1603 [[_dockContainerView superview] bringSubviewToFront:_dockContainerView];
1607 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1608 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1609 $addPerPageViews$([_iconModel iconLists]);
1610 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1613 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1614 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1616 [self setClipsToBounds:NO];
1620 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1621 static bool gssc(false);
1623 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1624 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1627 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1628 [Info_ setObject:[NSNumber numberWithBool:(
1630 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1631 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1632 )] forKey:@"UndockedIconLabels"];
1635 id &_label(MSHookIvar<id>(self, "_label"));
1636 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1639 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1640 [_label setInDock:docked];
1642 _SBIconLabel$setInDock$(self, sel, docked);
1643 [self setNeedsDisplay];
1646 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1647 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1650 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1651 _SBDockIconListView$setFrame$(self, sel, frame);
1654 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1655 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1656 NSString *identifier = [self bundleIdentifier];
1657 NSLocale *locale = [NSLocale currentLocale];
1658 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1660 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1661 NSString *file = table == nil ? @"Localizable" : table;
1662 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1663 NSDictionary *strings;
1664 if ((strings = [Strings_ objectForKey:name]) != nil) {
1665 if (static_cast<id>(strings) != [NSNull null]) strings:
1666 if (NSString *value = [strings objectForKey:key])
1668 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1671 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1672 [Strings_ setObject:[strings autorelease] forKey:name];
1676 [Strings_ setObject:[NSNull null] forKey:name];
1677 return MSOldCall(key, value, table);
1680 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1681 MSClassHook(WebCoreFrameBridge)
1683 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1686 void **core(reinterpret_cast<void **>([node _node]));
1687 if (core == NULL || core[6] == NULL)
1689 return MSOldCall(node, width);
1693 MSInstanceMessage1(void, SBIconLabel, drawRect, CGRect, rect) {
1694 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1697 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1698 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1700 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1702 NSString *style = [NSString stringWithFormat:@""
1703 "font-family: Helvetica; "
1704 "font-weight: bold; "
1706 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1707 ? @"font-size: 12px; "
1708 : @"font-size: 11px; "
1712 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1714 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1716 NSString *custom([Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")]);
1718 $drawLabel$(label, [self bounds], style, custom);
1721 MSInstanceMessage0(CGImageRef, SBIconLabel, buildLabelImage) {
1722 bool docked((MSHookIvar<unsigned>(self, "_inDock") & 0x2) != 0);
1724 WBStringDrawingState labelState = {NULL, 0, @""
1725 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1727 stringDrawingState_ = &labelState;
1730 CGImageRef image(MSOldCall());
1733 stringDrawingState_ = NULL;
1737 static bool wb$inDock(id parameters) {
1738 return [$objc_getAssociatedObject(parameters, @selector(wb$inDock)) boolValue];
1741 MSInstanceMessage0(NSUInteger, SBIconLabelImageParameters, hash) {
1742 return MSOldCall() + (wb$inDock(self) ? 0xdeadbeef : 0xd15ea5e);
1745 MSClassMessage2(id, SBIconView, _labelImageParametersForIcon,location, id, icon, int, location) {
1746 if (id parameters = MSOldCall(icon, location)) {
1747 $objc_setAssociatedObject(parameters, @selector(wb$inDock), [NSNumber numberWithBool:(location == 1)], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1752 MSClassMessage1(UIImage *, SBIconLabelImage, _drawLabelImageForParameters, id, parameters) {
1753 bool docked(wb$inDock(parameters));
1755 WBStringDrawingState labelState = {NULL, 0, @""
1756 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1758 stringDrawingState_ = &labelState;
1761 UIImage *image(MSOldCall(parameters));
1764 stringDrawingState_ = NULL;
1769 MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1770 if ((self = MSOldCall(frame, delegate)) != nil) {
1771 [self setBackgroundColor:[UIColor clearColor]];
1775 MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1776 return SMSBackgrounded_ ? NO : MSOldCall();
1779 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1780 [self wb$setBackgroundColor:[UIColor clearColor]];
1784 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1786 [balloon setBackgroundColor:[UIColor clearColor]];
1789 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1790 MSOldCall([UIColor clearColor]);
1791 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1795 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1796 if ((self = MSOldCall(style, reuse)) != nil) {
1797 [self setBackgroundColor:[UIColor clearColor]];
1798 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1803 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1804 if ((self = MSOldCall(style, reuse)) != nil) {
1805 [self setBackgroundColor:[UIColor clearColor]];
1806 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1810 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1811 if ((self = MSOldCall(style, reuse)) != nil) {
1812 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1813 [_label setBackgroundColor:[UIColor clearColor]];
1817 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1818 MSOldCall(UITableViewCellSeparatorStyleNone);
1821 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1822 if ((self = MSOldCall(frame, style)) != nil) {
1823 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1827 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1830 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1831 if (UIImage *image = $getImage$(path)) {
1832 SMSBackgrounded_ = true;
1834 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1835 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1837 if (&_transcriptTable != NULL)
1838 table = _transcriptTable;
1839 else if (&_transcriptLayer != NULL)
1840 table = _transcriptLayer;
1844 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1845 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1848 [placard insertSubview:background atIndex:0];
1850 [table setBackgroundColor:[UIColor clearColor]];
1851 [placard insertSubview:background belowSubview:table];
1857 // %hook _UIImageWithName() {{{
1858 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1860 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1867 if (_UIPackedImageTableGetIdentifierForName != NULL)
1868 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1869 else if (_UISharedImageNameGetIdentifier != NULL) {
1870 identifier = _UISharedImageNameGetIdentifier(name);
1871 packed = identifier != -1;
1878 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1881 return __UIImageWithName(name);
1883 NSNumber *key([NSNumber numberWithInt:identifier]);
1884 UIImage *image([UIImages_ objectForKey:key]);
1886 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1887 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1888 image = $getImage$(path);
1889 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1893 image = __UIImageWithName(name);
1896 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1897 if (![Manager_ fileExistsAtPath:path])
1898 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1905 // %hook _UIImageWithNameInDomain() {{{
1906 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1907 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1908 UIImage *image([PathImages_ objectForKey:key]);
1910 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1912 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1913 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1914 image = $getImage$(path);
1915 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1916 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1920 // %hook GSFontCreateWithName() {{{
1921 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1923 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1924 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1925 name = [font UTF8String];
1926 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1927 // size *= [scale floatValue];
1928 return _GSFontCreateWithName(name, traits, size);
1932 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1933 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1935 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1937 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1939 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1940 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1942 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1945 NSString *path = [NSString stringWithUTF8String:a1];
1946 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1947 NSString *file = [path substringFromIndex:31];
1948 for (NSString *theme in Themes_) {
1949 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1950 if ([Manager_ fileExistsAtPath:path]) {
1951 strcpy(a1, [path UTF8String]);
1960 static void ChangeWallpaper(
1961 CFNotificationCenterRef center,
1965 CFDictionaryRef info
1968 NSLog(@"WB:Debug:ChangeWallpaper!");
1971 if (WallpaperFile_ != nil) {
1972 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1974 image = [image autorelease];
1977 if (WallpaperImage_ != nil)
1978 [WallpaperImage_ setImage:image];
1979 if (WallpaperPage_ != nil)
1980 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1984 #define WBRename(name, sel, imp) \
1985 MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp, &_ ## name ## $ ## imp)
1987 template <typename Type_>
1988 static void msset(Type_ &function, MSImageRef image, const char *name) {
1989 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1992 template <typename Type_>
1993 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1994 struct nlist &name(nl[index]);
1995 uintptr_t value(name.n_value);
1996 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1997 value |= 0x00000001;
1998 function = reinterpret_cast<Type_>(value);
2001 template <typename Type_>
2002 static void dlset(Type_ &function, const char *name) {
2003 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
2006 // %hook CGImageReadCreateWithFile() {{{
2007 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
2009 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
2010 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2011 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
2016 MSHook(void *, CGImageSourceCreateWithFile, NSString *path, NSDictionary *options) {
2018 NSLog(@"WB:Debug: CGImageSourceCreateWithFile(%@, %@)", path, options);
2019 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2020 void *value(_CGImageSourceCreateWithFile([path wb$themedPath], options));
2025 MSHook(void *, CGImageSourceCreateWithURL, NSURL *url, NSDictionary *options) {
2027 NSLog(@"WB:Debug: CGImageSourceCreateWithURL(%@, %@)", url, options);
2028 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2029 if ([url isFileURL])
2030 url = [NSURL fileURLWithPath:[[url path] wb$themedPath]];
2031 void *value(_CGImageSourceCreateWithURL(url, options));
2037 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
2038 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
2039 if (style == nil || [style length] == 0)
2040 style = @"font-family: Helvetica; font-size: 12px";
2041 //NSLog(@"XXX:drawP(%@ | %@)", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
2042 [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
2045 static void NSString$drawInRect$withStyle$(NSString *self, SEL _cmd, CGRect rect, NSString *style) {
2046 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
2047 if (style == nil || [style length] == 0)
2048 style = @"font-family: Helvetica; font-size: 12px";
2049 //NSLog(@"XXX:drawR(%@ | %@)", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
2050 return [[WBMarkup sharedMarkup] drawString:self inRect:rect withStyle:style];
2053 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
2054 if (style == nil || [style length] == 0)
2055 style = @"font-family: Helvetica; font-size: 12px";
2056 CGSize size([[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width]);
2057 //NSLog(@"XXX:size(%@ | %@) = [%g %g]", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "], size.width, size.height);
2061 static void SBInitialize() {
2063 WBRename(SBApplication, pathForIcon, pathForIcon);
2064 WBRename(SBApplicationIcon, icon, icon);
2065 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
2068 WBRename(SBBookmarkIcon, icon, icon);
2069 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
2070 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
2071 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
2072 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
2074 WBRename(SBWidgetApplicationIcon, icon, icon);
2076 WBRename(SBDockIconListView, setFrame:, setFrame$);
2077 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
2079 if (kCFCoreFoundationVersionNumber < 600 || SummerBoard_)
2080 WBRename(SBIconLabel, drawRect:, drawRect$);
2081 else if (kCFCoreFoundationVersionNumber < 700) {
2082 WBRename(SBIconLabel, buildLabelImage, buildLabelImage);
2084 WBRename(SBIconLabelImageParameters, hash, hash);
2085 WBRename($SBIconView, _labelImageParametersForIcon:location:, _labelImageParametersForIcon$location$);
2086 WBRename($SBIconLabelImage, _drawLabelImageForParameters:, _drawLabelImageForParameters$);
2089 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
2090 WBRename(SBIconLabel, setInDock:, setInDock$);
2092 WBRename(SBIconList, didMoveToSuperview, didMoveToSuperview);
2093 WBRename(SBIconList, setFrame:, setFrame$);
2095 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
2096 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
2097 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
2098 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
2100 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
2101 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
2102 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
2104 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
2106 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
2107 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
2108 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
2109 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
2110 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
2111 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
2112 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
2113 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
2114 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
2117 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
2121 $objc_setAssociatedObject = reinterpret_cast<void (*)(id, void *, id value, objc_AssociationPolicy)>(dlsym(RTLD_DEFAULT, "objc_setAssociatedObject"));
2122 $objc_getAssociatedObject = reinterpret_cast<id (*)(id, void *)>(dlsym(RTLD_DEFAULT, "objc_getAssociatedObject"));
2123 $objc_removeAssociatedObjects = reinterpret_cast<void (*)(id)>(dlsym(RTLD_DEFAULT, "objc_removeAssociatedObjects"));
2125 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2127 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
2128 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
2130 Manager_ = [[NSFileManager defaultManager] retain];
2131 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
2133 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
2135 // Load Settings.plist {{{
2136 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
2137 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
2138 SummerBoard_ = [value boolValue];
2140 SummerBoard_ = true;
2142 if (NSNumber *value = [settings objectForKey:@"Debug"])
2143 Debug_ = [value boolValue];
2144 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
2145 UIDebug_ = [value boolValue];
2147 NSArray *themes([settings objectForKey:@"Themes"]);
2149 if (NSString *theme = [settings objectForKey:@"Theme"])
2150 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
2152 [NSNumber numberWithBool:true], @"Active",
2156 for (NSDictionary *theme in themes) {
2157 NSNumber *active([theme objectForKey:@"Active"]);
2158 if (![active boolValue])
2161 NSString *name([theme objectForKey:@"Name"]);
2165 NSString *theme(nil);
2167 #define testForTheme(format...) \
2168 if (theme == nil) { \
2169 NSString *path = [NSString stringWithFormat:format]; \
2170 if ([Manager_ fileExistsAtPath:path]) { \
2171 [Themes_ addObject:path]; \
2176 testForTheme(@"/Library/Themes/%@.theme", name)
2177 testForTheme(@"/Library/Themes/%@", name)
2178 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
2183 // Merge Info.plist {{{
2184 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2186 for (NSString *theme in Themes_)
2187 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
2188 for (NSString *key in [info allKeys])
2189 if ([Info_ objectForKey:key] == nil)
2190 [Info_ setObject:[info objectForKey:key] forKey:key];
2194 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
2195 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
2196 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
2199 // GraphicsServices {{{
2201 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
2205 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
2206 void *(*CGImageReadCreateWithFile)(NSString *, int);
2207 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
2208 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
2210 if (CGImageReadCreateWithFile == NULL) {
2211 void *(*CGImageSourceCreateWithFile)(NSString *, NSDictionary *);
2212 msset(CGImageSourceCreateWithFile, image, "_CGImageSourceCreateWithFile");
2213 MSHookFunction(CGImageSourceCreateWithFile, MSHake(CGImageSourceCreateWithFile));
2215 void *(*CGImageSourceCreateWithURL)(NSURL *, NSDictionary *);
2216 msset(CGImageSourceCreateWithURL, image, "_CGImageSourceCreateWithURL");
2217 MSHookFunction(CGImageSourceCreateWithURL, MSHake(CGImageSourceCreateWithURL));
2223 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
2224 Papered_ = $getTheme$(Wallpapers_) != nil;
2225 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
2227 CFNotificationCenterAddObserver(
2228 CFNotificationCenterGetDarwinNotifyCenter(),
2229 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
2232 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
2233 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
2234 if (MediaPlayer != nil)
2237 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
2238 $MPVideoView = objc_getClass("MPVideoView");
2245 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
2246 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
2247 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v28@0:4{CGRect={CGSize=ff}{CGSize=ff}}8@24");
2248 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
2251 memset(nl, 0, sizeof(nl));
2252 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
2253 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
2254 nl[2].n_un.n_name = (char *) "__UIKitBundle";
2255 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
2256 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
2259 nlset(_UIApplicationImageWithName, nl, 0);
2260 nlset(_UIImageWithNameInDomain, nl, 1);
2261 nlset(_UIKitBundle, nl, 2);
2262 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
2263 nlset(_UISharedImageNameGetIdentifier, nl, 4);
2265 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
2266 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
2267 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
2271 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
2272 NSError *error(nil);
2273 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
2274 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
2276 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);