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]];
272 [scaled addObject:[NSString stringWithFormat:@"%@@2x.%@", base, extension]];
275 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
277 // if (!IsWild_) <- support old themes
278 [scaled addObject:file];
279 } else if ([base hasSuffix: @"@2x"]) {
280 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
281 [scaled addObject:file];
283 // XXX: this actually can't be used, as the person loading the file doesn't realize that the @2x changed
284 /*NSString *rest([base substringWithRange:NSMakeRange(0, [base length] - 3)]);
285 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", rest, idiom, extension]];
286 [scaled addObject:[rest stringByAppendingPathExtension:extension]];*/
288 // XXX: this code isn't really complete
290 [scaled addObject:file];
292 if ([base hasSuffix:[NSString stringWithFormat:@"~%@", idiom]])
293 [scaled addObject:[[base substringWithRange:NSMakeRange(0, [base length] - 1 - [idiom length])] stringByAppendingPathExtension:extension]];
300 static NSString *$getTheme$(NSArray *files, NSArray *themes = Themes_) {
301 // XXX: this is not reasonable; OMG
304 @synchronized (Themed_) {
305 if (NSString *path = [Themed_ objectForKey:key])
306 return reinterpret_cast<id>(path) == [NSNull null] ? nil : path;
310 NSLog(@"WB:Debug: %@", [files description]);
314 for (NSString *theme in Themes_)
315 for (NSString *file in files) {
316 path = [NSString stringWithFormat:@"%@/%@", theme, file];
317 if ([Manager_ fileExistsAtPath:path])
324 @synchronized (Themed_) {
325 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:key];
331 // $pathForFile$inBundle$() {{{
332 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool ui) {
333 NSString *identifier = [bundle bundleIdentifier];
334 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
336 if (identifier != nil)
337 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
338 if (NSString *folder = [[bundle bundlePath] lastPathComponent]) {
339 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
340 NSString *base([folder stringByDeletingPathExtension]);
341 if ([base hasSuffix:@"~iphone"])
342 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 7)], [folder pathExtension], file]];
343 if ([base hasSuffix:@"~ipad"])
344 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 5)], [folder pathExtension], file]];
347 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
349 #define remapResourceName(oldname, newname) \
350 else if ([file isEqualToString:(oldname)]) \
351 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
353 bool summer(SpringBoard_ && SummerBoard_);
355 if (identifier == nil);
356 else if ([identifier isEqualToString:@"com.apple.chatkit"])
357 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
358 else if ([identifier isEqualToString:@"com.apple.calculator"])
359 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
361 remapResourceName(@"FSO_BG.png", @"StatusBar")
362 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
363 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
365 [names addObject:[NSString stringWithFormat:@"Fallback/%@", file]];
367 if (NSString *path = $getTheme$($useScale$(names, ui)))
374 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
375 NSString *identifier = [self bundleIdentifier];
376 NSString *path = [self path];
377 NSString *folder = [path lastPathComponent];
378 NSString *dname = [self displayName];
379 NSString *didentifier = [self displayIdentifier];
382 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
384 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
386 /* XXX: I might need to keep this for backwards compatibility
387 if (identifier != nil)
388 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
390 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
392 #define testForIcon(Name) \
393 if (NSString *name = Name) \
394 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
396 if (![didentifier isEqualToString:identifier])
397 testForIcon(didentifier);
399 testForIcon(identifier);
402 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
405 if (didentifier != nil) {
406 testForIcon([English_ objectForKey:didentifier]);
408 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
409 if ([parts count] != 1)
410 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
411 testForIcon([english objectForKey:[parts lastObject]]);
414 if (NSString *path = $getTheme$(names))
420 // -[NSBundle wb$bundleWithFile] {{{
421 @interface NSBundle (WinterBoard)
422 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
425 @implementation NSBundle (WinterBoard)
427 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
428 path = [path stringByDeletingLastPathComponent];
429 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
432 NSBundle *bundle([Bundles_ objectForKey:path]);
433 if (reinterpret_cast<id>(bundle) == [NSNull null])
435 else if (bundle == nil) {
436 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
437 bundle = [NSBundle bundleWithPath:path];
439 bundle = [NSBundle wb$bundleWithFile:path];
441 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
442 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
450 // -[NSString wb$themedPath] {{{
451 @interface NSString (WinterBoard)
452 - (NSString *) wb$themedPath;
455 @implementation NSString (WinterBoard)
457 - (NSString *) wb$themedPath {
458 if ([self hasPrefix:@"/Library/Themes/"])
462 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
464 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
465 NSString *file([self stringByResolvingSymlinksInPath]);
466 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
467 if ([file hasPrefix:prefix]) {
468 NSUInteger length([prefix length]);
469 if (length != [file length])
470 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
481 void WBLogRect(const char *tag, struct CGRect rect) {
482 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
485 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
486 CGRect frame([view frame]);
487 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]);
489 for (UIView *child in [view subviews])
490 WBLogHierarchy(child, index++, indent + 1);
493 UIImage *$cacheForImage$(UIImage *image) {
494 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
495 CGRect rect = {CGPointMake(1, 1), [image size]};
496 CGSize size = {rect.size.width + 2, rect.size.height + 2};
498 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
499 CGColorSpaceRelease(space);
501 CGContextDrawImage(context, rect, [image CGImage]);
502 CGImageRef ref(CGBitmapContextCreateImage(context));
503 CGContextRelease(context);
505 UIImage *cache([UIImage imageWithCGImage:ref]);
511 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
512 //if ([name isEqualToString:@"icons"]) return nil;
513 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
516 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
517 NSString *key([icon displayIdentifier]);
519 if (UIImage *image = [icon icon]) {
520 CGSize size = [image size];
521 if (size.width != 59 || size.height != 60) {
522 UIImage *cache($cacheForImage$(image));
523 [Cache_ setObject:cache forKey:key];
528 _SBIconModel$cacheImageForIcon$(self, sel, icon);
531 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
532 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
533 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
535 NSString *key([icon displayIdentifier]);
537 if (UIImage *image = [icon icon]) {
538 CGSize size = [image size];
539 if (size.width != 59 || size.height != 60) {
540 UIImage *cache($cacheForImage$(image));
541 [Cache_ setObject:cache forKey:key];
547 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
548 NSString *key([icon displayIdentifier]);
549 if (UIImage *image = [Cache_ objectForKey:key])
552 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
555 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
557 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
558 NSString *key([icon displayIdentifier]);
559 if (UIImage *image = [Cache_ objectForKey:key])
562 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
565 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
566 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
567 [self setBackgroundColor:[UIColor clearColor]];
568 for (UIView *child in [self subviews])
569 [child setBackgroundColor:[UIColor clearColor]];
573 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
574 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
575 [self setBackgroundColor:[UIColor clearColor]];
579 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
580 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
581 float inset([self edgeInset]);
582 [[UIColor clearColor] set];
583 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
584 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
587 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
588 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
589 if (NSString *path = $pathForIcon$([self application]))
590 return [UIImage imageWithContentsOfFile:path];
591 return _SBApplicationIcon$icon(self, sel);
594 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
596 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
597 if (IsWild_ && false) // XXX: delete this code, it should not be supported
598 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
599 return [UIImage imageWithContentsOfFile:path72];
600 if (NSString *path = $pathForIcon$([self application]))
601 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
603 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
604 width = [$SBIcon defaultIconImageSize].width;
607 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
610 return _SBApplicationIcon$generateIconImage$(self, sel, type);
613 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
615 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
616 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
617 return [UIImage imageWithContentsOfFile:path];
618 return _SBWidgetApplicationIcon$icon(self, sel);
621 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
623 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
624 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
625 return [UIImage imageWithContentsOfFile:path];
626 return _SBBookmarkIcon$icon(self, sel);
629 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
630 if (NSString *path = $pathForIcon$(self))
632 return _SBApplication$pathForIcon(self, sel);
635 static UIImage *CachedImageAtPath(NSString *path) {
636 path = [path stringByResolvingSymlinksInPath];
637 UIImage *image = [PathImages_ objectForKey:path];
639 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
640 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
642 image = [image autorelease];
643 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
647 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
648 NSBundle *bundle = [NSBundle mainBundle];
650 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
651 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
652 return CachedImageAtPath(path);
653 return __UIApplicationImageWithName(name);
656 #define WBDelegate(delegate) \
657 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
659 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
660 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
662 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
666 - (void) forwardInvocation:(NSInvocation*)inv { \
667 SEL sel = [inv selector]; \
668 if ([delegate respondsToSelector:sel]) \
669 [inv invokeWithTarget:delegate]; \
671 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
674 // %hook -[NSBundle pathForResource:ofType:] {{{
675 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
676 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
678 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
679 if (NSString *path = $pathForFile$inBundle$(file, self, false))
681 return MSOldCall(resource, type);
685 static void $drawLabel$(NSString *label, CGRect rect, NSString *style, NSString *custom) {
686 bool ellipsis(false);
687 float max = rect.size.width - 11, width;
689 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
692 size_t length([label length]);
693 float spacing((width - max) / (length - 1));
695 if (spacing > 1.25) {
697 label = [label substringToIndex:(length - 1)];
701 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
705 label = [label stringByAppendingString:@"..."];
708 style = [style stringByAppendingString:custom];
710 CGSize size = [label sizeWithStyle:style forWidth:rect.size.width];
711 [label drawAtPoint:CGPointMake((rect.size.width - size.width) / 2 + rect.origin.x, rect.origin.y) withStyle:style];
714 static struct WBStringDrawingState {
715 WBStringDrawingState *next_;
719 } *stringDrawingState_;
721 extern "C" CGColorSpaceRef CGContextGetFillColorSpace(CGContextRef);
722 extern "C" void CGContextGetFillColor(CGContextRef, CGFloat[]);
724 static NSString *WBColorMarkup() {
725 CGContextRef context(UIGraphicsGetCurrentContext());
726 //NSLog(@"XXX:1:%p", context);
730 CGColorSpaceRef space(CGContextGetFillColorSpace(context));
731 //NSLog(@"XXX:2:%p", space);
735 size_t number(CGColorSpaceGetNumberOfComponents(space));
736 //NSLog(@"XXX:3:%u", number);
740 CGFloat components[number + 1];
741 CGContextGetFillColor(context, components);
764 return [NSString stringWithFormat:@"color: rgba(%g, %g, %g, %g)", r * 255, g * 255, b * 255, a];
767 MSInstanceMessageHook6(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode,letterSpacing,includeEmoji, CGPoint, point, float, width, UIFont *, font, UILineBreakMode, mode, float, spacing, BOOL, emoji) {
768 //NSLog(@"XXX: @\"%@\" %g", self, spacing);
770 WBStringDrawingState *state(stringDrawingState_);
772 return MSOldCall(point, width, font, mode, spacing, emoji);
774 if (--state->count_ == 0)
775 stringDrawingState_ = state->next_;
776 if (state->info_ == nil)
777 return MSOldCall(point, width, font, mode, spacing, emoji);
779 NSString *info([Info_ objectForKey:state->info_]);
781 return MSOldCall(point, width, font, mode, spacing, emoji);
783 NSString *base(state->base_ ?: @"");
784 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
785 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
789 extern "C" NSString *NSStringFromCGRect(CGRect rect);
791 MSInstanceMessageHook7(CGSize, NSString, _drawInRect,withFont,lineBreakMode,alignment,lineSpacing,includeEmoji,truncationRect, CGRect, rect, UIFont *, font, UILineBreakMode, mode, UITextAlignment, alignment, float, spacing, BOOL, emoji, CGRect, truncation) {
792 //NSLog(@"XXX: &\"%@\" %@ \"%@\" %u %u %g %u %@", self, NSStringFromCGRect(rect), font, mode, alignment, spacing, emoji, NSStringFromCGRect(truncation));
794 WBStringDrawingState *state(stringDrawingState_);
796 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
798 if (--state->count_ == 0)
799 stringDrawingState_ = state->next_;
800 if (state->info_ == nil)
801 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
803 NSString *info([Info_ objectForKey:state->info_]);
805 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
810 case UITextAlignmentLeft:
813 case UITextAlignmentCenter:
814 textAlign = @"center";
816 case UITextAlignmentRight:
817 textAlign = @"right";
821 NSString *base(state->base_ ?: @"");
822 NSString *extra([NSString stringWithFormat:@"text-align: %@", textAlign]);
825 $drawLabel$(self, rect, [NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], WBColorMarkup(), base], info);
827 [self drawInRect:rect withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
832 MSInstanceMessageHook4(CGSize, NSString, sizeWithFont,forWidth,lineBreakMode,letterSpacing, UIFont *, font, float, width, UILineBreakMode, mode, float, spacing) {
833 //NSLog(@"XXX: #\"%@\" \"%@\" %g %u %g", self, font, width, mode, spacing);
835 WBStringDrawingState *state(stringDrawingState_);
837 return MSOldCall(font, width, mode, spacing);
839 if (--state->count_ == 0)
840 stringDrawingState_ = state->next_;
841 if (state->info_ == nil)
842 return MSOldCall(font, width, mode, spacing);
844 NSString *info([Info_ objectForKey:state->info_]);
846 return MSOldCall(font, width, mode, spacing);
848 NSString *base(state->base_ ?: @"");
849 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
850 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info] forWidth:width];
853 MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) {
854 //NSLog(@"XXX: ?\"%@\"", self);
856 WBStringDrawingState *state(stringDrawingState_);
858 return MSOldCall(font);
860 if (--state->count_ == 0)
861 stringDrawingState_ = state->next_;
862 if (state->info_ == nil)
863 return MSOldCall(font);
865 NSString *info([Info_ objectForKey:state->info_]);
867 return MSOldCall(font);
869 NSString *base(state->base_ ?: @"");
870 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), base, info] forWidth:65535];
873 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
874 WBStringDrawingState badgeState = {NULL, -1, @""
877 stringDrawingState_ = &badgeState;
879 UIImage *image(MSOldCall(text));
881 stringDrawingState_ = NULL;
885 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
886 WBStringDrawingState dayState = {NULL, 2, @""
887 // XXX: this is only correct on an iPod dock
888 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
889 , @"CalendarIconDayStyle"};
891 WBStringDrawingState sizeState = {&dayState, 7, nil, nil};
893 WBStringDrawingState dateState = {&sizeState, 2, @""
894 , @"CalendarIconDateStyle"};
896 stringDrawingState_ = &dateState;
898 UIImage *image(MSOldCall(type));
900 stringDrawingState_ = NULL;
904 MSInstanceMessageHook1(UIImage *, UIStatusBarTimeItemView, contentsImageForStyle, int, style) {
905 WBStringDrawingState timeState = {NULL, 0, @""
908 stringDrawingState_ = &timeState;
910 UIImage *image(MSOldCall(style));
912 stringDrawingState_ = NULL;
916 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
917 NSBundle *bundle([NSBundle mainBundle]);
919 CFLocaleRef locale(CFLocaleCopyCurrent());
920 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
923 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
925 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
926 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
927 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
928 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
932 CFRelease(formatter);
934 NSString *datestyle([@""
935 "font-family: Helvetica; "
936 "font-weight: bold; "
939 "" stringByAppendingString:(IsWild_
940 ? @"font-size: 54px; "
941 : @"font-size: 39px; "
944 NSString *daystyle([@""
945 "font-family: Helvetica; "
946 "font-weight: bold; "
948 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
949 "" stringByAppendingString:(IsWild_
950 ? @"font-size: 11px; "
951 : @"font-size: 9px; "
954 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
955 datestyle = [datestyle stringByAppendingString:style];
956 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
957 daystyle = [daystyle stringByAppendingString:style];
959 float width([self bounds].size.width);
961 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
962 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
964 unsigned base0(IsWild_ ? 89 : 70);
965 if ($GSFontGetUseLegacyFontMetrics())
967 unsigned base1(IsWild_ ? 18 : 16);
974 [(NSString *)date drawAtPoint:CGPointMake(
975 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
976 ) withStyle:datestyle];
978 [(NSString *)day drawAtPoint:CGPointMake(
979 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
980 ) withStyle:daystyle];
986 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
987 void $setBarStyle$_(NSString *name, int &style) {
989 NSLog(@"WB:Debug:%@Style:%d", name, style);
990 NSNumber *number = nil;
992 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
994 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
996 style = [number intValue];
998 NSLog(@"WB:Debug:%@Style=%d", name, style);
1002 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
1003 $setBarStyle$_(@"Toolbar", style);
1004 return MSOldCall(style);
1007 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
1008 $setBarStyle$_(@"NavigationBar", style);
1009 return MSOldCall(style);
1013 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
1014 [[self superview] setBackgroundColor:[UIColor clearColor]];
1015 _SBButtonBar$didMoveToSuperview(self, sel);
1018 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
1019 [[self superview] setBackgroundColor:[UIColor clearColor]];
1020 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
1023 static NSArray *Wallpapers_;
1024 static bool Papered_;
1025 static bool Docked_;
1026 static bool SMSBackgrounded_;
1027 static NSString *WallpaperFile_;
1028 static UIImageView *WallpaperImage_;
1029 static UIWebDocumentView *WallpaperPage_;
1030 static NSURL *WallpaperURL_;
1032 #define _release(object) \
1033 do if (object != nil) { \
1038 static UIImage *$getImage$(NSString *path) {
1039 UIImage *image([UIImage imageWithContentsOfFile:path]);
1041 unsigned scale($getScale$(path));
1042 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
1043 [image setScale:scale];
1048 static UIImage *$getDefaultDesktopImage$() {
1049 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
1050 return $getImage$(path);
1054 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
1055 return $getDefaultDesktopImage$() ?: MSOldCall();
1058 MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
1059 return $getDefaultDesktopImage$() ?: MSOldCall();
1062 MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
1063 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
1064 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
1065 if (UIImage *image = $getDefaultDesktopImage$()) {
1066 [self setImage:image];
1076 // %hook -[SBUIController init] {{{
1077 MSInstanceMessageHook0(id, SBUIController, init) {
1082 NSString *paper($getTheme$(Wallpapers_));
1084 paper = [paper stringByDeletingLastPathComponent];
1088 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
1089 char *machine = new char[size];
1091 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
1092 perror("sysctlbyname(\"hw.machine\", ?)");
1097 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
1101 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
1104 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
1105 if (&_wallpaperView != NULL) {
1106 [_wallpaperView removeFromSuperview];
1107 [_wallpaperView release];
1108 _wallpaperView = nil;
1112 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
1113 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
1116 if (&_contentLayer != NULL)
1117 player = &_contentLayer;
1118 else if (&_contentView != NULL)
1119 player = &_contentView;
1122 UIView *layer(player == NULL ? nil : *player);
1124 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
1125 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
1126 [window setContentView:content];
1128 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
1129 [window setBackgroundColor:[_window backgroundColor]];
1130 [_window setBackgroundColor:[UIColor clearColor]];
1132 [window setLevel:-1000];
1133 [window setHidden:NO];
1135 /*if (player != NULL)
1136 *player = content;*/
1138 [content setBackgroundColor:[layer backgroundColor]];
1139 [layer setBackgroundColor:[UIColor clearColor]];
1142 if (!SummerBoard_ || !IsWild_)
1145 CGRect bounds([content bounds]);
1146 bounds.origin.y = -30;
1147 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
1148 [content addSubview:indirect];
1149 [indirect zoomToScale:2.4];
1152 _release(WallpaperFile_);
1153 _release(WallpaperImage_);
1154 _release(WallpaperPage_);
1155 _release(WallpaperURL_);
1158 NSArray *themes([NSArray arrayWithObject:paper]);
1160 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1164 static AVController *controller_(nil);
1165 if (controller_ == nil) {
1166 AVQueue *queue([AVQueue avQueue]);
1167 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1170 AVQueue *queue([controller_ queue]);
1172 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1173 [controller_ setLayer:[video _layer]];
1175 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1176 [queue appendItem:item error:&error];
1178 [controller_ play:&error];
1179 #elif UseMPMoviePlayerController
1180 NSURL *url([NSURL fileURLWithPath:path]);
1181 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1182 controller.movieControlMode = MPMovieControlModeHidden;
1185 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1186 [video setMovieWithPath:path];
1187 [video setRepeatMode:1];
1188 [video setRepeatGap:-1];
1189 [video playFromBeginning];;
1192 [indirect addSubview:video];
1195 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1196 if (UIImage *image = $getImage$(path)) {
1197 WallpaperFile_ = [path retain];
1198 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1199 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1200 [WallpaperImage_ setAlpha:[number floatValue]];
1201 [indirect addSubview:WallpaperImage_];
1205 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1206 CGRect bounds = [indirect bounds];
1208 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1209 [view setAutoresizes:true];
1211 WallpaperPage_ = [view retain];
1212 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1214 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1216 [view setBackgroundColor:[UIColor clearColor]];
1217 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1218 [view setDrawsBackground:NO];
1219 [[view webView] setDrawsBackground:NO];
1221 [indirect addSubview:view];
1225 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1226 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1227 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1228 if ([Manager_ fileExistsAtPath:html]) {
1229 CGRect bounds = [indirect bounds];
1231 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1232 [view setAutoresizes:true];
1234 NSURL *url = [NSURL fileURLWithPath:html];
1235 [view loadRequest:[NSURLRequest requestWithURL:url]];
1237 [view setBackgroundColor:[UIColor clearColor]];
1238 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1239 [view setDrawsBackground:NO];
1240 [[view webView] setDrawsBackground:NO];
1242 [indirect addSubview:view];
1250 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1251 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1252 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1254 if (path != nil && _backgroundView != nil)
1257 _SBAwayView$updateDesktopImage$(self, sel, image);
1260 CGRect bounds = [self bounds];
1262 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1263 [view setAutoresizes:true];
1265 if (WallpaperPage_ != nil)
1266 [WallpaperPage_ release];
1267 WallpaperPage_ = [view retain];
1269 if (WallpaperURL_ != nil)
1270 [WallpaperURL_ release];
1271 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1273 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1275 [[view webView] setDrawsBackground:false];
1276 [view setBackgroundColor:[UIColor clearColor]];
1278 [self insertSubview:view aboveSubview:_backgroundView];
1282 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1283 extern "C" CGColorRef CGGStateGetFillColor(void *);
1284 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1285 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1287 /* WBTimeLabel {{{ */
1288 @interface WBTimeLabel : NSProxy {
1290 _transient SBStatusBarTimeView *view_;
1293 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1297 @implementation WBTimeLabel
1304 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1305 time_ = [time retain];
1310 - (NSString *) description {
1316 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1317 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1318 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1320 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1321 "font-family: Helvetica; "
1322 "font-weight: bold; "
1325 "%@", _mode ? @"white" : @"black", custom]];
1330 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1335 /* WBBadgeLabel {{{ */
1336 @interface WBBadgeLabel : NSProxy {
1340 - (id) initWithBadge:(NSString *)badge;
1341 - (NSString *) description;
1345 @implementation WBBadgeLabel
1352 - (id) initWithBadge:(NSString *)badge {
1353 badge_ = [badge retain];
1357 - (NSString *) description {
1358 return [badge_ description];
1363 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1364 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1365 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1366 "font-family: Helvetica; "
1367 "font-weight: bold; "
1375 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1382 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1383 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1384 alpha = [number floatValue];
1385 return MSOldCall(alpha);
1388 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1389 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1390 alpha = [number floatValue];
1391 return MSOldCall(alpha);
1394 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1395 if ((self = MSOldCall()) != nil) {
1396 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1397 // XXX: note: this is overridden above, which is silly
1398 float alpha([number floatValue]);
1399 if ([self respondsToSelector:@selector(setIconImageAlpha:)])
1400 [self setIconImageAlpha:alpha];
1401 if ([self respondsToSelector:@selector(setIconLabelAlpha:)])
1402 [self setIconLabelAlpha:alpha];
1403 if ([self respondsToSelector:@selector(setAlpha:)])
1404 [self setAlpha:alpha];
1409 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1410 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1411 alpha = [number floatValue];
1412 return MSOldCall(alpha);
1416 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1417 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1418 id &_badge(MSHookIvar<id>(self, "_badge"));
1420 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1425 void SBStatusBarController$setStatusBarMode(int &mode) {
1427 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1428 if (mode < 100) // 104:hidden 105:glowing
1429 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1430 mode = [number intValue];
1433 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1434 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1435 SBStatusBarController$setStatusBarMode(mode);
1436 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1439 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1440 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1441 SBStatusBarController$setStatusBarMode(mode);
1442 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1445 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) {
1446 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1447 SBStatusBarController$setStatusBarMode(mode);
1448 //NSLog(@"mode=%u", mode);
1449 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1452 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1453 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1454 mode = [number intValue];
1455 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1458 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1459 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1461 NSLog(@"operatorNameStyle= %@", style);
1462 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1463 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1467 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1469 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1470 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1473 // XXX: replace this with [SBStatusBarTimeView tile]
1474 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1475 id &_time(MSHookIvar<id>(self, "_time"));
1476 if (_time != nil && [_time class] != [WBTimeLabel class])
1477 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1478 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1481 @interface UIView (WinterBoard)
1482 - (bool) wb$isWBImageView;
1483 - (void) wb$logHierarchy;
1484 - (void) wb$setBackgroundColor:(UIColor *)color;
1487 @implementation UIView (WinterBoard)
1489 - (bool) wb$isWBImageView {
1493 - (void) wb$logHierarchy {
1494 WBLogHierarchy(self);
1497 - (void) wb$setBackgroundColor:(UIColor *)color {
1498 [self setBackgroundColor:color];
1499 for (UIView *child in [self subviews])
1500 [child wb$setBackgroundColor:color];
1505 @interface WBImageView : UIImageView {
1508 - (bool) wb$isWBImageView;
1509 - (void) wb$updateFrame;
1512 @implementation WBImageView
1514 - (bool) wb$isWBImageView {
1518 - (void) wb$updateFrame {
1519 CGRect frame([self frame]);
1522 for (UIView *view(self); ; ) {
1523 view = [view superview];
1526 frame.origin.y -= [view frame].origin.y;
1529 [self setFrame:frame];
1534 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1535 NSArray *subviews([self subviews]);
1536 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1537 if (view != nil && [view wb$isWBImageView])
1538 [view wb$updateFrame];
1539 _SBIconList$setFrame$(self, sel, frame);
1542 static void $addPerPageView$(unsigned i, UIView *list) {
1543 NSString *path($getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]]));
1547 NSArray *subviews([list subviews]);
1549 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1550 if (view == nil || ![view wb$isWBImageView]) {
1551 view = [[[WBImageView alloc] init] autorelease];
1552 [list insertSubview:view atIndex:0];
1555 UIImage *image([UIImage imageWithContentsOfFile:path]);
1557 CGRect frame([view frame]);
1558 frame.size = [image size];
1559 [view setFrame:frame];
1561 [view setImage:image];
1562 [view wb$updateFrame];
1565 static void $addPerPageViews$(NSArray *lists) {
1566 for (unsigned i(0), e([lists count]); i != e; ++i)
1567 $addPerPageView$(i, [lists objectAtIndex:i]);
1570 MSInstanceMessageHook0(void, SBIconController, updateNumberOfRootIconLists) {
1571 NSArray *&_rootIconLists(MSHookIvar<NSArray *>(self, "_rootIconLists"));
1572 $addPerPageViews$(_rootIconLists);
1576 MSInstanceMessageHook0(void, SBIconContentView, layoutSubviews) {
1579 if (SBIconController *controller = [$SBIconController sharedInstance]) {
1580 UIView *&_dockContainerView(MSHookIvar<UIView *>(controller, "_dockContainerView"));
1581 if (&_dockContainerView != NULL)
1582 [[_dockContainerView superview] bringSubviewToFront:_dockContainerView];
1586 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1587 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1588 $addPerPageViews$([_iconModel iconLists]);
1589 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1592 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1593 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1595 [self setClipsToBounds:NO];
1599 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1600 static bool gssc(false);
1602 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1603 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1606 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1607 [Info_ setObject:[NSNumber numberWithBool:(
1609 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1610 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1611 )] forKey:@"UndockedIconLabels"];
1614 id &_label(MSHookIvar<id>(self, "_label"));
1615 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1618 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1619 [_label setInDock:docked];
1621 _SBIconLabel$setInDock$(self, sel, docked);
1622 [self setNeedsDisplay];
1625 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1626 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1629 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1630 _SBDockIconListView$setFrame$(self, sel, frame);
1633 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1634 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1635 NSString *identifier = [self bundleIdentifier];
1636 NSLocale *locale = [NSLocale currentLocale];
1637 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1639 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1640 NSString *file = table == nil ? @"Localizable" : table;
1641 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1642 NSDictionary *strings;
1643 if ((strings = [Strings_ objectForKey:name]) != nil) {
1644 if (static_cast<id>(strings) != [NSNull null]) strings:
1645 if (NSString *value = [strings objectForKey:key])
1647 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1650 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1651 [Strings_ setObject:[strings autorelease] forKey:name];
1655 [Strings_ setObject:[NSNull null] forKey:name];
1656 return MSOldCall(key, value, table);
1659 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1660 MSClassHook(WebCoreFrameBridge)
1662 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1665 void **core(reinterpret_cast<void **>([node _node]));
1666 if (core == NULL || core[6] == NULL)
1668 return MSOldCall(node, width);
1672 MSInstanceMessage1(void, SBIconLabel, drawRect, CGRect, rect) {
1673 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1676 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1677 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1679 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1681 NSString *style = [NSString stringWithFormat:@""
1682 "font-family: Helvetica; "
1683 "font-weight: bold; "
1685 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1686 ? @"font-size: 12px; "
1687 : @"font-size: 11px; "
1691 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1693 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1695 NSString *custom([Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")]);
1697 $drawLabel$(label, [self bounds], style, custom);
1700 MSInstanceMessage0(CGImageRef, SBIconLabel, buildLabelImage) {
1701 bool docked((MSHookIvar<unsigned>(self, "_inDock") & 0x2) != 0);
1703 WBStringDrawingState labelState = {NULL, 0, @""
1704 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1706 stringDrawingState_ = &labelState;
1709 CGImageRef image(MSOldCall());
1712 stringDrawingState_ = NULL;
1717 MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1718 if ((self = MSOldCall(frame, delegate)) != nil) {
1719 [self setBackgroundColor:[UIColor clearColor]];
1723 MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1724 return SMSBackgrounded_ ? NO : MSOldCall();
1727 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1728 [self wb$setBackgroundColor:[UIColor clearColor]];
1732 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1734 [balloon setBackgroundColor:[UIColor clearColor]];
1737 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1738 MSOldCall([UIColor clearColor]);
1739 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1743 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1744 if ((self = MSOldCall(style, reuse)) != nil) {
1745 [self setBackgroundColor:[UIColor clearColor]];
1746 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1751 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1752 if ((self = MSOldCall(style, reuse)) != nil) {
1753 [self setBackgroundColor:[UIColor clearColor]];
1754 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1758 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1759 if ((self = MSOldCall(style, reuse)) != nil) {
1760 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1761 [_label setBackgroundColor:[UIColor clearColor]];
1765 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1766 MSOldCall(UITableViewCellSeparatorStyleNone);
1769 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1770 if ((self = MSOldCall(frame, style)) != nil) {
1771 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1775 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1778 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1779 if (UIImage *image = $getImage$(path)) {
1780 SMSBackgrounded_ = true;
1782 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1783 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1785 if (&_transcriptTable != NULL)
1786 table = _transcriptTable;
1787 else if (&_transcriptLayer != NULL)
1788 table = _transcriptLayer;
1792 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1793 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1796 [placard insertSubview:background atIndex:0];
1798 [table setBackgroundColor:[UIColor clearColor]];
1799 [placard insertSubview:background belowSubview:table];
1805 // %hook _UIImageWithName() {{{
1806 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1808 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1815 if (_UIPackedImageTableGetIdentifierForName != NULL)
1816 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1817 else if (_UISharedImageNameGetIdentifier != NULL) {
1818 identifier = _UISharedImageNameGetIdentifier(name);
1819 packed = identifier != -1;
1826 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1829 return __UIImageWithName(name);
1831 NSNumber *key([NSNumber numberWithInt:identifier]);
1832 UIImage *image([UIImages_ objectForKey:key]);
1834 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1835 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1836 image = $getImage$(path);
1837 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1841 image = __UIImageWithName(name);
1844 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1845 if (![Manager_ fileExistsAtPath:path])
1846 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1853 // %hook _UIImageWithNameInDomain() {{{
1854 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1855 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1856 UIImage *image([PathImages_ objectForKey:key]);
1858 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1860 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1861 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1862 image = $getImage$(path);
1863 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1864 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1868 // %hook GSFontCreateWithName() {{{
1869 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1871 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1872 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1873 name = [font UTF8String];
1874 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1875 // size *= [scale floatValue];
1876 return _GSFontCreateWithName(name, traits, size);
1880 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1881 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1883 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1885 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1887 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1888 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1890 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1893 NSString *path = [NSString stringWithUTF8String:a1];
1894 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1895 NSString *file = [path substringFromIndex:31];
1896 for (NSString *theme in Themes_) {
1897 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1898 if ([Manager_ fileExistsAtPath:path]) {
1899 strcpy(a1, [path UTF8String]);
1908 static void ChangeWallpaper(
1909 CFNotificationCenterRef center,
1913 CFDictionaryRef info
1916 NSLog(@"WB:Debug:ChangeWallpaper!");
1919 if (WallpaperFile_ != nil) {
1920 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1922 image = [image autorelease];
1925 if (WallpaperImage_ != nil)
1926 [WallpaperImage_ setImage:image];
1927 if (WallpaperPage_ != nil)
1928 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1932 #define WBRename(name, sel, imp) \
1933 MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp, &_ ## name ## $ ## imp)
1935 template <typename Type_>
1936 static void msset(Type_ &function, MSImageRef image, const char *name) {
1937 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1940 template <typename Type_>
1941 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1942 struct nlist &name(nl[index]);
1943 uintptr_t value(name.n_value);
1944 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1945 value |= 0x00000001;
1946 function = reinterpret_cast<Type_>(value);
1949 template <typename Type_>
1950 static void dlset(Type_ &function, const char *name) {
1951 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1954 // %hook CGImageReadCreateWithFile() {{{
1955 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1957 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1958 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1959 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1965 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
1966 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1967 if (style == nil || [style length] == 0)
1968 style = @"font-family: Helvetica; font-size: 12px";
1969 //NSLog(@"XXX:drawP(%@)", [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
1970 return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
1973 static void NSString$drawInRect$withStyle$(NSString *self, SEL _cmd, CGRect rect, NSString *style) {
1974 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1975 if (style == nil || [style length] == 0)
1976 style = @"font-family: Helvetica; font-size: 12px";
1977 //NSLog(@"XXX:drawR(%@)", [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
1978 return [[WBMarkup sharedMarkup] drawString:self inRect:rect withStyle:style];
1981 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
1982 if (style == nil || [style length] == 0)
1983 style = @"font-family: Helvetica; font-size: 12px";
1984 //NSLog(@"XXX:size(%@)", [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
1985 return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width];
1988 static void SBInitialize() {
1990 WBRename(SBApplication, pathForIcon, pathForIcon);
1991 WBRename(SBApplicationIcon, icon, icon);
1992 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1995 WBRename(SBBookmarkIcon, icon, icon);
1996 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1997 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1998 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1999 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
2001 WBRename(SBWidgetApplicationIcon, icon, icon);
2003 WBRename(SBDockIconListView, setFrame:, setFrame$);
2004 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
2006 if (kCFCoreFoundationVersionNumber < 600 || SummerBoard_)
2007 WBRename(SBIconLabel, drawRect:, drawRect$);
2009 WBRename(SBIconLabel, buildLabelImage, buildLabelImage);
2011 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
2012 WBRename(SBIconLabel, setInDock:, setInDock$);
2014 WBRename(SBIconList, setFrame:, setFrame$);
2016 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
2017 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
2018 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
2019 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
2021 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
2022 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
2023 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
2025 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
2027 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
2028 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
2029 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
2030 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
2031 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
2032 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
2033 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
2034 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
2035 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
2038 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
2042 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2044 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
2045 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
2047 Manager_ = [[NSFileManager defaultManager] retain];
2048 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
2050 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
2052 // Load Settings.plist {{{
2053 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
2054 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
2055 SummerBoard_ = [value boolValue];
2057 SummerBoard_ = true;
2059 if (NSNumber *value = [settings objectForKey:@"Debug"])
2060 Debug_ = [value boolValue];
2061 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
2062 UIDebug_ = [value boolValue];
2064 NSArray *themes([settings objectForKey:@"Themes"]);
2066 if (NSString *theme = [settings objectForKey:@"Theme"])
2067 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
2069 [NSNumber numberWithBool:true], @"Active",
2073 for (NSDictionary *theme in themes) {
2074 NSNumber *active([theme objectForKey:@"Active"]);
2075 if (![active boolValue])
2078 NSString *name([theme objectForKey:@"Name"]);
2082 NSString *theme(nil);
2084 #define testForTheme(format...) \
2085 if (theme == nil) { \
2086 NSString *path = [NSString stringWithFormat:format]; \
2087 if ([Manager_ fileExistsAtPath:path]) { \
2088 [Themes_ addObject:path]; \
2093 testForTheme(@"/Library/Themes/%@.theme", name)
2094 testForTheme(@"/Library/Themes/%@", name)
2095 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
2100 // Merge Info.plist {{{
2101 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2103 for (NSString *theme in Themes_)
2104 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
2105 for (NSString *key in [info allKeys])
2106 if ([Info_ objectForKey:key] == nil)
2107 [Info_ setObject:[info objectForKey:key] forKey:key];
2111 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
2112 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
2113 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
2116 // GraphicsServices {{{
2118 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
2122 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
2123 void *(*CGImageReadCreateWithFile)(NSString *, int);
2124 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
2125 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
2130 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
2131 Papered_ = $getTheme$(Wallpapers_) != nil;
2132 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
2134 CFNotificationCenterAddObserver(
2135 CFNotificationCenterGetDarwinNotifyCenter(),
2136 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
2139 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
2140 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
2141 if (MediaPlayer != nil)
2144 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
2145 $MPVideoView = objc_getClass("MPVideoView");
2152 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
2153 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
2154 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v28@0:4{CGRect={CGSize=ff}{CGSize=ff}}8@24");
2155 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
2158 memset(nl, 0, sizeof(nl));
2159 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
2160 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
2161 nl[2].n_un.n_name = (char *) "__UIKitBundle";
2162 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
2163 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
2166 nlset(_UIApplicationImageWithName, nl, 0);
2167 nlset(_UIImageWithNameInDomain, nl, 1);
2168 nlset(_UIKitBundle, nl, 2);
2169 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
2170 nlset(_UISharedImageNameGetIdentifier, nl, 4);
2172 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
2173 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
2174 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
2178 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
2179 NSError *error(nil);
2180 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
2181 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
2183 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);