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]) {
318 if ([[Manager_ pathContentOfSymbolicLinkAtPath:path] isEqualToString:@"/"])
327 @synchronized (Themed_) {
328 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:key];
334 // $pathForFile$inBundle$() {{{
335 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool ui) {
336 NSString *identifier = [bundle bundleIdentifier];
337 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
339 if (identifier != nil)
340 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
341 if (NSString *folder = [[bundle bundlePath] lastPathComponent]) {
342 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
343 NSString *base([folder stringByDeletingPathExtension]);
344 if ([base hasSuffix:@"~iphone"])
345 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 7)], [folder pathExtension], file]];
346 if ([base hasSuffix:@"~ipad"])
347 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 5)], [folder pathExtension], file]];
350 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
352 #define remapResourceName(oldname, newname) \
353 else if ([file isEqualToString:(oldname)]) \
354 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
356 bool summer(SpringBoard_ && SummerBoard_);
358 if (identifier == nil);
359 else if ([identifier isEqualToString:@"com.apple.chatkit"])
360 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
361 else if ([identifier isEqualToString:@"com.apple.calculator"])
362 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
364 remapResourceName(@"FSO_BG.png", @"StatusBar")
365 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
366 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
368 [names addObject:[NSString stringWithFormat:@"Fallback/%@", file]];
370 if (NSString *path = $getTheme$($useScale$(names, ui)))
377 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
378 NSString *identifier = [self bundleIdentifier];
379 NSString *path = [self path];
380 NSString *folder = [path lastPathComponent];
381 NSString *dname = [self displayName];
382 NSString *didentifier = [self displayIdentifier];
385 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
387 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
389 /* XXX: I might need to keep this for backwards compatibility
390 if (identifier != nil)
391 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
393 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
395 #define testForIcon(Name) \
396 if (NSString *name = Name) \
397 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
399 if (![didentifier isEqualToString:identifier])
400 testForIcon(didentifier);
402 testForIcon(identifier);
405 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
408 if (didentifier != nil) {
409 testForIcon([English_ objectForKey:didentifier]);
411 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
412 if ([parts count] != 1)
413 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
414 testForIcon([english objectForKey:[parts lastObject]]);
417 if (NSString *path = $getTheme$(names))
423 // -[NSBundle wb$bundleWithFile] {{{
424 @interface NSBundle (WinterBoard)
425 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
428 @implementation NSBundle (WinterBoard)
430 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
431 path = [path stringByDeletingLastPathComponent];
432 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
435 NSBundle *bundle([Bundles_ objectForKey:path]);
436 if (reinterpret_cast<id>(bundle) == [NSNull null])
438 else if (bundle == nil) {
439 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
440 bundle = [NSBundle bundleWithPath:path];
442 bundle = [NSBundle wb$bundleWithFile:path];
444 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
445 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
453 // -[NSString wb$themedPath] {{{
454 @interface NSString (WinterBoard)
455 - (NSString *) wb$themedPath;
458 @implementation NSString (WinterBoard)
460 - (NSString *) wb$themedPath {
461 if ([self hasPrefix:@"/Library/Themes/"])
465 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
467 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
468 NSString *file([self stringByResolvingSymlinksInPath]);
469 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
470 if ([file hasPrefix:prefix]) {
471 NSUInteger length([prefix length]);
472 if (length != [file length])
473 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
484 void WBLogRect(const char *tag, struct CGRect rect) {
485 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
488 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
489 CGRect frame([view frame]);
490 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]);
492 for (UIView *child in [view subviews])
493 WBLogHierarchy(child, index++, indent + 1);
496 UIImage *$cacheForImage$(UIImage *image) {
497 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
498 CGRect rect = {CGPointMake(1, 1), [image size]};
499 CGSize size = {rect.size.width + 2, rect.size.height + 2};
501 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
502 CGColorSpaceRelease(space);
504 CGContextDrawImage(context, rect, [image CGImage]);
505 CGImageRef ref(CGBitmapContextCreateImage(context));
506 CGContextRelease(context);
508 UIImage *cache([UIImage imageWithCGImage:ref]);
514 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
515 //if ([name isEqualToString:@"icons"]) return nil;
516 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
519 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
520 NSString *key([icon displayIdentifier]);
522 if (UIImage *image = [icon icon]) {
523 CGSize size = [image size];
524 if (size.width != 59 || size.height != 60) {
525 UIImage *cache($cacheForImage$(image));
526 [Cache_ setObject:cache forKey:key];
531 _SBIconModel$cacheImageForIcon$(self, sel, icon);
534 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
535 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
536 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
538 NSString *key([icon displayIdentifier]);
540 if (UIImage *image = [icon icon]) {
541 CGSize size = [image size];
542 if (size.width != 59 || size.height != 60) {
543 UIImage *cache($cacheForImage$(image));
544 [Cache_ setObject:cache forKey:key];
550 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
551 NSString *key([icon displayIdentifier]);
552 if (UIImage *image = [Cache_ objectForKey:key])
555 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
558 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
560 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
561 NSString *key([icon displayIdentifier]);
562 if (UIImage *image = [Cache_ objectForKey:key])
565 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
568 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
569 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
570 [self setBackgroundColor:[UIColor clearColor]];
571 for (UIView *child in [self subviews])
572 [child setBackgroundColor:[UIColor clearColor]];
576 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
577 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
578 [self setBackgroundColor:[UIColor clearColor]];
582 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
583 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
584 float inset([self edgeInset]);
585 [[UIColor clearColor] set];
586 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
587 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
590 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
591 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
592 if (NSString *path = $pathForIcon$([self application]))
593 return [UIImage imageWithContentsOfFile:path];
594 return _SBApplicationIcon$icon(self, sel);
597 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
599 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
600 if (IsWild_ && false) // XXX: delete this code, it should not be supported
601 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
602 return [UIImage imageWithContentsOfFile:path72];
603 if (NSString *path = $pathForIcon$([self application]))
604 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
606 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
607 width = [$SBIcon defaultIconImageSize].width;
610 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
613 return _SBApplicationIcon$generateIconImage$(self, sel, type);
616 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
618 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
619 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
620 return [UIImage imageWithContentsOfFile:path];
621 return _SBWidgetApplicationIcon$icon(self, sel);
624 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
626 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
627 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
628 return [UIImage imageWithContentsOfFile:path];
629 return _SBBookmarkIcon$icon(self, sel);
632 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
633 if (NSString *path = $pathForIcon$(self))
635 return _SBApplication$pathForIcon(self, sel);
638 static UIImage *CachedImageAtPath(NSString *path) {
639 path = [path stringByResolvingSymlinksInPath];
640 UIImage *image = [PathImages_ objectForKey:path];
642 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
643 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
645 image = [image autorelease];
646 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
650 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
651 NSBundle *bundle = [NSBundle mainBundle];
653 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
654 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
655 return CachedImageAtPath(path);
656 return __UIApplicationImageWithName(name);
659 #define WBDelegate(delegate) \
660 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
662 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
663 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
665 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
669 - (void) forwardInvocation:(NSInvocation*)inv { \
670 SEL sel = [inv selector]; \
671 if ([delegate respondsToSelector:sel]) \
672 [inv invokeWithTarget:delegate]; \
674 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
677 // %hook -[NSBundle pathForResource:ofType:] {{{
678 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
679 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
681 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
682 if (NSString *path = $pathForFile$inBundle$(file, self, false))
684 return MSOldCall(resource, type);
688 static void $drawLabel$(NSString *label, CGRect rect, NSString *style, NSString *custom) {
689 bool ellipsis(false);
690 float max = rect.size.width - 11, width;
692 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
695 size_t length([label length]);
696 float spacing((width - max) / (length - 1));
698 if (spacing > 1.25) {
700 label = [label substringToIndex:(length - 1)];
704 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
708 label = [label stringByAppendingString:@"..."];
711 style = [style stringByAppendingString:custom];
713 CGSize size = [label sizeWithStyle:style forWidth:rect.size.width];
714 [label drawAtPoint:CGPointMake((rect.size.width - size.width) / 2 + rect.origin.x, rect.origin.y) withStyle:style];
717 static struct WBStringDrawingState {
718 WBStringDrawingState *next_;
722 } *stringDrawingState_;
724 extern "C" CGColorSpaceRef CGContextGetFillColorSpace(CGContextRef);
725 extern "C" void CGContextGetFillColor(CGContextRef, CGFloat[]);
727 static NSString *WBColorMarkup() {
728 CGContextRef context(UIGraphicsGetCurrentContext());
729 //NSLog(@"XXX:1:%p", context);
733 CGColorSpaceRef space(CGContextGetFillColorSpace(context));
734 //NSLog(@"XXX:2:%p", space);
738 size_t number(CGColorSpaceGetNumberOfComponents(space));
739 //NSLog(@"XXX:3:%u", number);
743 CGFloat components[number + 1];
744 CGContextGetFillColor(context, components);
767 return [NSString stringWithFormat:@"color: rgba(%g, %g, %g, %g)", r * 255, g * 255, b * 255, a];
770 MSInstanceMessageHook6(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode,letterSpacing,includeEmoji, CGPoint, point, float, width, UIFont *, font, UILineBreakMode, mode, float, spacing, BOOL, emoji) {
771 //NSLog(@"XXX: @\"%@\" %g", self, spacing);
773 WBStringDrawingState *state(stringDrawingState_);
775 return MSOldCall(point, width, font, mode, spacing, emoji);
777 if (--state->count_ == 0)
778 stringDrawingState_ = state->next_;
779 if (state->info_ == nil)
780 return MSOldCall(point, width, font, mode, spacing, emoji);
782 NSString *info([Info_ objectForKey:state->info_]);
784 return MSOldCall(point, width, font, mode, spacing, emoji);
786 NSString *base(state->base_ ?: @"");
787 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
788 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
792 extern "C" NSString *NSStringFromCGRect(CGRect rect);
794 MSInstanceMessageHook7(CGSize, NSString, _drawInRect,withFont,lineBreakMode,alignment,lineSpacing,includeEmoji,truncationRect, CGRect, rect, UIFont *, font, UILineBreakMode, mode, UITextAlignment, alignment, float, spacing, BOOL, emoji, CGRect, truncation) {
795 //NSLog(@"XXX: &\"%@\" %@ \"%@\" %u %u %g %u %@", self, NSStringFromCGRect(rect), font, mode, alignment, spacing, emoji, NSStringFromCGRect(truncation));
797 WBStringDrawingState *state(stringDrawingState_);
799 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
801 if (--state->count_ == 0)
802 stringDrawingState_ = state->next_;
803 if (state->info_ == nil)
804 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
806 NSString *info([Info_ objectForKey:state->info_]);
808 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
813 case UITextAlignmentLeft:
816 case UITextAlignmentCenter:
817 textAlign = @"center";
819 case UITextAlignmentRight:
820 textAlign = @"right";
824 NSString *base(state->base_ ?: @"");
825 NSString *extra([NSString stringWithFormat:@"text-align: %@", textAlign]);
828 $drawLabel$(self, rect, [NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], WBColorMarkup(), base], info);
830 [self drawInRect:rect withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
835 MSInstanceMessageHook4(CGSize, NSString, sizeWithFont,forWidth,lineBreakMode,letterSpacing, UIFont *, font, float, width, UILineBreakMode, mode, float, spacing) {
836 //NSLog(@"XXX: #\"%@\" \"%@\" %g %u %g", self, font, width, mode, spacing);
838 WBStringDrawingState *state(stringDrawingState_);
840 return MSOldCall(font, width, mode, spacing);
842 if (--state->count_ == 0)
843 stringDrawingState_ = state->next_;
844 if (state->info_ == nil)
845 return MSOldCall(font, width, mode, spacing);
847 NSString *info([Info_ objectForKey:state->info_]);
849 return MSOldCall(font, width, mode, spacing);
851 NSString *base(state->base_ ?: @"");
852 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
853 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info] forWidth:width];
856 MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) {
857 //NSLog(@"XXX: ?\"%@\"", self);
859 WBStringDrawingState *state(stringDrawingState_);
861 return MSOldCall(font);
863 if (--state->count_ == 0)
864 stringDrawingState_ = state->next_;
865 if (state->info_ == nil)
866 return MSOldCall(font);
868 NSString *info([Info_ objectForKey:state->info_]);
870 return MSOldCall(font);
872 NSString *base(state->base_ ?: @"");
873 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), base, info] forWidth:65535];
876 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
877 WBStringDrawingState badgeState = {NULL, -1, @""
880 stringDrawingState_ = &badgeState;
882 UIImage *image(MSOldCall(text));
884 stringDrawingState_ = NULL;
888 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
889 WBStringDrawingState dayState = {NULL, 2, @""
890 // XXX: this is only correct on an iPod dock
891 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
892 , @"CalendarIconDayStyle"};
894 WBStringDrawingState sizeState = {&dayState, 7, nil, nil};
896 WBStringDrawingState dateState = {&sizeState, 2, @""
897 , @"CalendarIconDateStyle"};
899 stringDrawingState_ = &dateState;
901 UIImage *image(MSOldCall(type));
903 stringDrawingState_ = NULL;
907 MSInstanceMessageHook1(UIImage *, UIStatusBarTimeItemView, contentsImageForStyle, int, style) {
908 WBStringDrawingState timeState = {NULL, 0, @""
911 stringDrawingState_ = &timeState;
913 UIImage *image(MSOldCall(style));
915 stringDrawingState_ = NULL;
919 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
920 NSBundle *bundle([NSBundle mainBundle]);
922 CFLocaleRef locale(CFLocaleCopyCurrent());
923 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
926 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
928 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
929 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
930 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
931 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
935 CFRelease(formatter);
937 NSString *datestyle([@""
938 "font-family: Helvetica; "
939 "font-weight: bold; "
942 "" stringByAppendingString:(IsWild_
943 ? @"font-size: 54px; "
944 : @"font-size: 39px; "
947 NSString *daystyle([@""
948 "font-family: Helvetica; "
949 "font-weight: bold; "
951 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
952 "" stringByAppendingString:(IsWild_
953 ? @"font-size: 11px; "
954 : @"font-size: 9px; "
957 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
958 datestyle = [datestyle stringByAppendingString:style];
959 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
960 daystyle = [daystyle stringByAppendingString:style];
962 float width([self bounds].size.width);
964 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
965 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
967 unsigned base0(IsWild_ ? 89 : 70);
968 if ($GSFontGetUseLegacyFontMetrics())
970 unsigned base1(IsWild_ ? 18 : 16);
977 [(NSString *)date drawAtPoint:CGPointMake(
978 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
979 ) withStyle:datestyle];
981 [(NSString *)day drawAtPoint:CGPointMake(
982 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
983 ) withStyle:daystyle];
989 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
990 void $setBarStyle$_(NSString *name, int &style) {
992 NSLog(@"WB:Debug:%@Style:%d", name, style);
993 NSNumber *number = nil;
995 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
997 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
999 style = [number intValue];
1001 NSLog(@"WB:Debug:%@Style=%d", name, style);
1005 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
1006 $setBarStyle$_(@"Toolbar", style);
1007 return MSOldCall(style);
1010 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
1011 $setBarStyle$_(@"NavigationBar", style);
1012 return MSOldCall(style);
1016 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
1017 [[self superview] setBackgroundColor:[UIColor clearColor]];
1018 _SBButtonBar$didMoveToSuperview(self, sel);
1021 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
1022 [[self superview] setBackgroundColor:[UIColor clearColor]];
1023 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
1026 static NSArray *Wallpapers_;
1027 static bool Papered_;
1028 static bool Docked_;
1029 static bool SMSBackgrounded_;
1030 static NSString *WallpaperFile_;
1031 static UIImageView *WallpaperImage_;
1032 static UIWebDocumentView *WallpaperPage_;
1033 static NSURL *WallpaperURL_;
1035 #define _release(object) \
1036 do if (object != nil) { \
1041 static UIImage *$getImage$(NSString *path) {
1042 UIImage *image([UIImage imageWithContentsOfFile:path]);
1044 unsigned scale($getScale$(path));
1045 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
1046 [image setScale:scale];
1051 static UIImage *$getDefaultDesktopImage$() {
1052 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
1053 return $getImage$(path);
1057 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
1058 return $getDefaultDesktopImage$() ?: MSOldCall();
1061 MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
1062 return $getDefaultDesktopImage$() ?: MSOldCall();
1065 MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
1066 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
1067 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
1068 if (UIImage *image = $getDefaultDesktopImage$()) {
1069 [self setImage:image];
1079 // %hook -[SBUIController init] {{{
1080 MSInstanceMessageHook0(id, SBUIController, init) {
1085 NSString *paper($getTheme$(Wallpapers_));
1087 paper = [paper stringByDeletingLastPathComponent];
1091 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
1092 char *machine = new char[size];
1094 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
1095 perror("sysctlbyname(\"hw.machine\", ?)");
1100 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
1104 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
1107 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
1108 if (&_wallpaperView != NULL) {
1109 [_wallpaperView removeFromSuperview];
1110 [_wallpaperView release];
1111 _wallpaperView = nil;
1115 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
1116 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
1119 if (&_contentLayer != NULL)
1120 player = &_contentLayer;
1121 else if (&_contentView != NULL)
1122 player = &_contentView;
1125 UIView *layer(player == NULL ? nil : *player);
1127 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
1128 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
1129 [window setContentView:content];
1131 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
1132 [window setBackgroundColor:[_window backgroundColor]];
1133 [_window setBackgroundColor:[UIColor clearColor]];
1135 [window setLevel:-1000];
1136 [window setHidden:NO];
1138 /*if (player != NULL)
1139 *player = content;*/
1141 [content setBackgroundColor:[layer backgroundColor]];
1142 [layer setBackgroundColor:[UIColor clearColor]];
1145 if (!SummerBoard_ || !IsWild_)
1148 CGRect bounds([content bounds]);
1149 bounds.origin.y = -30;
1150 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
1151 [content addSubview:indirect];
1152 [indirect zoomToScale:2.4];
1155 _release(WallpaperFile_);
1156 _release(WallpaperImage_);
1157 _release(WallpaperPage_);
1158 _release(WallpaperURL_);
1161 NSArray *themes([NSArray arrayWithObject:paper]);
1163 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1167 static AVController *controller_(nil);
1168 if (controller_ == nil) {
1169 AVQueue *queue([AVQueue avQueue]);
1170 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1173 AVQueue *queue([controller_ queue]);
1175 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1176 [controller_ setLayer:[video _layer]];
1178 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1179 [queue appendItem:item error:&error];
1181 [controller_ play:&error];
1182 #elif UseMPMoviePlayerController
1183 NSURL *url([NSURL fileURLWithPath:path]);
1184 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1185 controller.movieControlMode = MPMovieControlModeHidden;
1188 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1189 [video setMovieWithPath:path];
1190 [video setRepeatMode:1];
1191 [video setRepeatGap:-1];
1192 [video playFromBeginning];;
1195 [indirect addSubview:video];
1198 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1199 if (UIImage *image = $getImage$(path)) {
1200 WallpaperFile_ = [path retain];
1201 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1202 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1203 [WallpaperImage_ setAlpha:[number floatValue]];
1204 [indirect addSubview:WallpaperImage_];
1208 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1209 CGRect bounds = [indirect bounds];
1211 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1212 [view setAutoresizes:true];
1214 WallpaperPage_ = [view retain];
1215 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1217 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1219 [view setBackgroundColor:[UIColor clearColor]];
1220 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1221 [view setDrawsBackground:NO];
1222 [[view webView] setDrawsBackground:NO];
1224 [indirect addSubview:view];
1228 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1229 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1230 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1231 if ([Manager_ fileExistsAtPath:html]) {
1232 CGRect bounds = [indirect bounds];
1234 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1235 [view setAutoresizes:true];
1237 NSURL *url = [NSURL fileURLWithPath:html];
1238 [view loadRequest:[NSURLRequest requestWithURL:url]];
1240 [view setBackgroundColor:[UIColor clearColor]];
1241 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1242 [view setDrawsBackground:NO];
1243 [[view webView] setDrawsBackground:NO];
1245 [indirect addSubview:view];
1253 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1254 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1255 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1257 if (path != nil && _backgroundView != nil)
1260 _SBAwayView$updateDesktopImage$(self, sel, image);
1263 CGRect bounds = [self bounds];
1265 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1266 [view setAutoresizes:true];
1268 if (WallpaperPage_ != nil)
1269 [WallpaperPage_ release];
1270 WallpaperPage_ = [view retain];
1272 if (WallpaperURL_ != nil)
1273 [WallpaperURL_ release];
1274 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1276 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1278 [[view webView] setDrawsBackground:false];
1279 [view setBackgroundColor:[UIColor clearColor]];
1281 [self insertSubview:view aboveSubview:_backgroundView];
1285 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1286 extern "C" CGColorRef CGGStateGetFillColor(void *);
1287 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1288 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1290 /* WBTimeLabel {{{ */
1291 @interface WBTimeLabel : NSProxy {
1293 _transient SBStatusBarTimeView *view_;
1296 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1300 @implementation WBTimeLabel
1307 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1308 time_ = [time retain];
1313 - (NSString *) description {
1319 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1320 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1321 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1323 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1324 "font-family: Helvetica; "
1325 "font-weight: bold; "
1328 "%@", _mode ? @"white" : @"black", custom]];
1333 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1338 /* WBBadgeLabel {{{ */
1339 @interface WBBadgeLabel : NSProxy {
1343 - (id) initWithBadge:(NSString *)badge;
1344 - (NSString *) description;
1348 @implementation WBBadgeLabel
1355 - (id) initWithBadge:(NSString *)badge {
1356 badge_ = [badge retain];
1360 - (NSString *) description {
1361 return [badge_ description];
1366 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1367 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1368 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1369 "font-family: Helvetica; "
1370 "font-weight: bold; "
1378 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1385 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1386 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1387 alpha = [number floatValue];
1388 return MSOldCall(alpha);
1391 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1392 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1393 alpha = [number floatValue];
1394 return MSOldCall(alpha);
1397 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1398 if ((self = MSOldCall()) != nil) {
1399 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1400 // XXX: note: this is overridden above, which is silly
1401 float alpha([number floatValue]);
1402 if ([self respondsToSelector:@selector(setIconImageAlpha:)])
1403 [self setIconImageAlpha:alpha];
1404 if ([self respondsToSelector:@selector(setIconLabelAlpha:)])
1405 [self setIconLabelAlpha:alpha];
1406 if ([self respondsToSelector:@selector(setAlpha:)])
1407 [self setAlpha:alpha];
1412 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1413 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1414 alpha = [number floatValue];
1415 return MSOldCall(alpha);
1419 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1420 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1421 id &_badge(MSHookIvar<id>(self, "_badge"));
1423 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1428 void SBStatusBarController$setStatusBarMode(int &mode) {
1430 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1431 if (mode < 100) // 104:hidden 105:glowing
1432 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1433 mode = [number intValue];
1436 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1437 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1438 SBStatusBarController$setStatusBarMode(mode);
1439 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1442 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1443 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1444 SBStatusBarController$setStatusBarMode(mode);
1445 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1448 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) {
1449 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1450 SBStatusBarController$setStatusBarMode(mode);
1451 //NSLog(@"mode=%u", mode);
1452 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1455 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1456 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1457 mode = [number intValue];
1458 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1461 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1462 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1464 NSLog(@"operatorNameStyle= %@", style);
1465 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1466 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1470 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1472 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1473 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1476 // XXX: replace this with [SBStatusBarTimeView tile]
1477 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1478 id &_time(MSHookIvar<id>(self, "_time"));
1479 if (_time != nil && [_time class] != [WBTimeLabel class])
1480 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1481 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1484 @interface UIView (WinterBoard)
1485 - (bool) wb$isWBImageView;
1486 - (void) wb$logHierarchy;
1487 - (void) wb$setBackgroundColor:(UIColor *)color;
1490 @implementation UIView (WinterBoard)
1492 - (bool) wb$isWBImageView {
1496 - (void) wb$logHierarchy {
1497 WBLogHierarchy(self);
1500 - (void) wb$setBackgroundColor:(UIColor *)color {
1501 [self setBackgroundColor:color];
1502 for (UIView *child in [self subviews])
1503 [child wb$setBackgroundColor:color];
1508 @interface WBImageView : UIImageView {
1511 - (bool) wb$isWBImageView;
1512 - (void) wb$updateFrame;
1515 @implementation WBImageView
1517 - (bool) wb$isWBImageView {
1521 - (void) wb$updateFrame {
1522 CGRect frame([self frame]);
1525 for (UIView *view(self); ; ) {
1526 view = [view superview];
1529 frame.origin.y -= [view frame].origin.y;
1532 [self setFrame:frame];
1537 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1538 NSArray *subviews([self subviews]);
1539 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1540 if (view != nil && [view wb$isWBImageView])
1541 [view wb$updateFrame];
1542 _SBIconList$setFrame$(self, sel, frame);
1545 static void $addPerPageView$(unsigned i, UIView *list) {
1546 NSString *path($getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]]));
1550 NSArray *subviews([list subviews]);
1552 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1553 if (view == nil || ![view wb$isWBImageView]) {
1554 view = [[[WBImageView alloc] init] autorelease];
1555 [list insertSubview:view atIndex:0];
1558 UIImage *image([UIImage imageWithContentsOfFile:path]);
1560 CGRect frame([view frame]);
1561 frame.size = [image size];
1562 [view setFrame:frame];
1564 [view setImage:image];
1565 [view wb$updateFrame];
1568 static void $addPerPageViews$(NSArray *lists) {
1569 for (unsigned i(0), e([lists count]); i != e; ++i)
1570 $addPerPageView$(i, [lists objectAtIndex:i]);
1573 MSInstanceMessageHook0(void, SBIconController, updateNumberOfRootIconLists) {
1574 NSArray *&_rootIconLists(MSHookIvar<NSArray *>(self, "_rootIconLists"));
1575 $addPerPageViews$(_rootIconLists);
1579 MSInstanceMessageHook0(void, SBIconContentView, layoutSubviews) {
1582 if (SBIconController *controller = [$SBIconController sharedInstance]) {
1583 UIView *&_dockContainerView(MSHookIvar<UIView *>(controller, "_dockContainerView"));
1584 if (&_dockContainerView != NULL)
1585 [[_dockContainerView superview] bringSubviewToFront:_dockContainerView];
1589 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1590 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1591 $addPerPageViews$([_iconModel iconLists]);
1592 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1595 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1596 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1598 [self setClipsToBounds:NO];
1602 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1603 static bool gssc(false);
1605 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1606 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1609 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1610 [Info_ setObject:[NSNumber numberWithBool:(
1612 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1613 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1614 )] forKey:@"UndockedIconLabels"];
1617 id &_label(MSHookIvar<id>(self, "_label"));
1618 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1621 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1622 [_label setInDock:docked];
1624 _SBIconLabel$setInDock$(self, sel, docked);
1625 [self setNeedsDisplay];
1628 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1629 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1632 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1633 _SBDockIconListView$setFrame$(self, sel, frame);
1636 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1637 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1638 NSString *identifier = [self bundleIdentifier];
1639 NSLocale *locale = [NSLocale currentLocale];
1640 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1642 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1643 NSString *file = table == nil ? @"Localizable" : table;
1644 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1645 NSDictionary *strings;
1646 if ((strings = [Strings_ objectForKey:name]) != nil) {
1647 if (static_cast<id>(strings) != [NSNull null]) strings:
1648 if (NSString *value = [strings objectForKey:key])
1650 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1653 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1654 [Strings_ setObject:[strings autorelease] forKey:name];
1658 [Strings_ setObject:[NSNull null] forKey:name];
1659 return MSOldCall(key, value, table);
1662 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1663 MSClassHook(WebCoreFrameBridge)
1665 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1668 void **core(reinterpret_cast<void **>([node _node]));
1669 if (core == NULL || core[6] == NULL)
1671 return MSOldCall(node, width);
1675 MSInstanceMessage1(void, SBIconLabel, drawRect, CGRect, rect) {
1676 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1679 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1680 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1682 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1684 NSString *style = [NSString stringWithFormat:@""
1685 "font-family: Helvetica; "
1686 "font-weight: bold; "
1688 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1689 ? @"font-size: 12px; "
1690 : @"font-size: 11px; "
1694 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1696 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1698 NSString *custom([Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")]);
1700 $drawLabel$(label, [self bounds], style, custom);
1703 MSInstanceMessage0(CGImageRef, SBIconLabel, buildLabelImage) {
1704 bool docked((MSHookIvar<unsigned>(self, "_inDock") & 0x2) != 0);
1706 WBStringDrawingState labelState = {NULL, 0, @""
1707 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1709 stringDrawingState_ = &labelState;
1712 CGImageRef image(MSOldCall());
1715 stringDrawingState_ = NULL;
1720 MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1721 if ((self = MSOldCall(frame, delegate)) != nil) {
1722 [self setBackgroundColor:[UIColor clearColor]];
1726 MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1727 return SMSBackgrounded_ ? NO : MSOldCall();
1730 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1731 [self wb$setBackgroundColor:[UIColor clearColor]];
1735 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1737 [balloon setBackgroundColor:[UIColor clearColor]];
1740 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1741 MSOldCall([UIColor clearColor]);
1742 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1746 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1747 if ((self = MSOldCall(style, reuse)) != nil) {
1748 [self setBackgroundColor:[UIColor clearColor]];
1749 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1754 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1755 if ((self = MSOldCall(style, reuse)) != nil) {
1756 [self setBackgroundColor:[UIColor clearColor]];
1757 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1761 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1762 if ((self = MSOldCall(style, reuse)) != nil) {
1763 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1764 [_label setBackgroundColor:[UIColor clearColor]];
1768 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1769 MSOldCall(UITableViewCellSeparatorStyleNone);
1772 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1773 if ((self = MSOldCall(frame, style)) != nil) {
1774 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1778 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1781 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1782 if (UIImage *image = $getImage$(path)) {
1783 SMSBackgrounded_ = true;
1785 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1786 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1788 if (&_transcriptTable != NULL)
1789 table = _transcriptTable;
1790 else if (&_transcriptLayer != NULL)
1791 table = _transcriptLayer;
1795 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1796 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1799 [placard insertSubview:background atIndex:0];
1801 [table setBackgroundColor:[UIColor clearColor]];
1802 [placard insertSubview:background belowSubview:table];
1808 // %hook _UIImageWithName() {{{
1809 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1811 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1818 if (_UIPackedImageTableGetIdentifierForName != NULL)
1819 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1820 else if (_UISharedImageNameGetIdentifier != NULL) {
1821 identifier = _UISharedImageNameGetIdentifier(name);
1822 packed = identifier != -1;
1829 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1832 return __UIImageWithName(name);
1834 NSNumber *key([NSNumber numberWithInt:identifier]);
1835 UIImage *image([UIImages_ objectForKey:key]);
1837 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1838 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1839 image = $getImage$(path);
1840 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1844 image = __UIImageWithName(name);
1847 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1848 if (![Manager_ fileExistsAtPath:path])
1849 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1856 // %hook _UIImageWithNameInDomain() {{{
1857 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1858 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1859 UIImage *image([PathImages_ objectForKey:key]);
1861 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1863 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1864 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1865 image = $getImage$(path);
1866 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1867 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1871 // %hook GSFontCreateWithName() {{{
1872 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1874 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1875 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1876 name = [font UTF8String];
1877 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1878 // size *= [scale floatValue];
1879 return _GSFontCreateWithName(name, traits, size);
1883 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1884 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1886 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1888 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1890 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1891 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1893 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1896 NSString *path = [NSString stringWithUTF8String:a1];
1897 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1898 NSString *file = [path substringFromIndex:31];
1899 for (NSString *theme in Themes_) {
1900 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1901 if ([Manager_ fileExistsAtPath:path]) {
1902 strcpy(a1, [path UTF8String]);
1911 static void ChangeWallpaper(
1912 CFNotificationCenterRef center,
1916 CFDictionaryRef info
1919 NSLog(@"WB:Debug:ChangeWallpaper!");
1922 if (WallpaperFile_ != nil) {
1923 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1925 image = [image autorelease];
1928 if (WallpaperImage_ != nil)
1929 [WallpaperImage_ setImage:image];
1930 if (WallpaperPage_ != nil)
1931 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1935 #define WBRename(name, sel, imp) \
1936 MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp, &_ ## name ## $ ## imp)
1938 template <typename Type_>
1939 static void msset(Type_ &function, MSImageRef image, const char *name) {
1940 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1943 template <typename Type_>
1944 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1945 struct nlist &name(nl[index]);
1946 uintptr_t value(name.n_value);
1947 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1948 value |= 0x00000001;
1949 function = reinterpret_cast<Type_>(value);
1952 template <typename Type_>
1953 static void dlset(Type_ &function, const char *name) {
1954 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1957 // %hook CGImageReadCreateWithFile() {{{
1958 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1960 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1961 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1962 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1968 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
1969 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1970 if (style == nil || [style length] == 0)
1971 style = @"font-family: Helvetica; font-size: 12px";
1972 //NSLog(@"XXX:drawP(%@)", [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
1973 return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
1976 static void NSString$drawInRect$withStyle$(NSString *self, SEL _cmd, CGRect rect, NSString *style) {
1977 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1978 if (style == nil || [style length] == 0)
1979 style = @"font-family: Helvetica; font-size: 12px";
1980 //NSLog(@"XXX:drawR(%@)", [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
1981 return [[WBMarkup sharedMarkup] drawString:self inRect:rect withStyle:style];
1984 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
1985 if (style == nil || [style length] == 0)
1986 style = @"font-family: Helvetica; font-size: 12px";
1987 //NSLog(@"XXX:size(%@)", [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
1988 return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width];
1991 static void SBInitialize() {
1993 WBRename(SBApplication, pathForIcon, pathForIcon);
1994 WBRename(SBApplicationIcon, icon, icon);
1995 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1998 WBRename(SBBookmarkIcon, icon, icon);
1999 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
2000 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
2001 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
2002 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
2004 WBRename(SBWidgetApplicationIcon, icon, icon);
2006 WBRename(SBDockIconListView, setFrame:, setFrame$);
2007 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
2009 if (kCFCoreFoundationVersionNumber < 600 || SummerBoard_)
2010 WBRename(SBIconLabel, drawRect:, drawRect$);
2012 WBRename(SBIconLabel, buildLabelImage, buildLabelImage);
2014 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
2015 WBRename(SBIconLabel, setInDock:, setInDock$);
2017 WBRename(SBIconList, setFrame:, setFrame$);
2019 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
2020 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
2021 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
2022 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
2024 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
2025 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
2026 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
2028 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
2030 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
2031 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
2032 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
2033 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
2034 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
2035 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
2036 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
2037 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
2038 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
2041 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
2045 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2047 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
2048 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
2050 Manager_ = [[NSFileManager defaultManager] retain];
2051 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
2053 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
2055 // Load Settings.plist {{{
2056 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
2057 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
2058 SummerBoard_ = [value boolValue];
2060 SummerBoard_ = true;
2062 if (NSNumber *value = [settings objectForKey:@"Debug"])
2063 Debug_ = [value boolValue];
2064 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
2065 UIDebug_ = [value boolValue];
2067 NSArray *themes([settings objectForKey:@"Themes"]);
2069 if (NSString *theme = [settings objectForKey:@"Theme"])
2070 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
2072 [NSNumber numberWithBool:true], @"Active",
2076 for (NSDictionary *theme in themes) {
2077 NSNumber *active([theme objectForKey:@"Active"]);
2078 if (![active boolValue])
2081 NSString *name([theme objectForKey:@"Name"]);
2085 NSString *theme(nil);
2087 #define testForTheme(format...) \
2088 if (theme == nil) { \
2089 NSString *path = [NSString stringWithFormat:format]; \
2090 if ([Manager_ fileExistsAtPath:path]) { \
2091 [Themes_ addObject:path]; \
2096 testForTheme(@"/Library/Themes/%@.theme", name)
2097 testForTheme(@"/Library/Themes/%@", name)
2098 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
2103 // Merge Info.plist {{{
2104 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2106 for (NSString *theme in Themes_)
2107 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
2108 for (NSString *key in [info allKeys])
2109 if ([Info_ objectForKey:key] == nil)
2110 [Info_ setObject:[info objectForKey:key] forKey:key];
2114 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
2115 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
2116 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
2119 // GraphicsServices {{{
2121 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
2125 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
2126 void *(*CGImageReadCreateWithFile)(NSString *, int);
2127 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
2128 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
2133 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
2134 Papered_ = $getTheme$(Wallpapers_) != nil;
2135 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
2137 CFNotificationCenterAddObserver(
2138 CFNotificationCenterGetDarwinNotifyCenter(),
2139 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
2142 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
2143 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
2144 if (MediaPlayer != nil)
2147 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
2148 $MPVideoView = objc_getClass("MPVideoView");
2155 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
2156 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
2157 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v28@0:4{CGRect={CGSize=ff}{CGSize=ff}}8@24");
2158 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
2161 memset(nl, 0, sizeof(nl));
2162 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
2163 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
2164 nl[2].n_un.n_name = (char *) "__UIKitBundle";
2165 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
2166 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
2169 nlset(_UIApplicationImageWithName, nl, 0);
2170 nlset(_UIImageWithNameInDomain, nl, 1);
2171 nlset(_UIKitBundle, nl, 2);
2172 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
2173 nlset(_UISharedImageNameGetIdentifier, nl, 4);
2175 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
2176 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
2177 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
2181 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
2182 NSError *error(nil);
2183 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
2184 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
2186 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);