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 static void SBIconList$updateFrames$(SBIconList *self) {
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];
1544 MSHook(void, SBIconList$didMoveToSuperview, SBIconList *self, SEL sel) {
1545 SBIconList$updateFrames$(self);
1546 _SBIconList$didMoveToSuperview(self, sel);
1549 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1550 SBIconList$updateFrames$(self);
1551 _SBIconList$setFrame$(self, sel, frame);
1554 static void $addPerPageView$(unsigned i, UIView *list) {
1555 NSString *path($getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]]));
1559 NSArray *subviews([list subviews]);
1561 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1562 if (view == nil || ![view wb$isWBImageView]) {
1563 view = [[[WBImageView alloc] init] autorelease];
1564 [list insertSubview:view atIndex:0];
1567 UIImage *image([UIImage imageWithContentsOfFile:path]);
1569 CGRect frame([view frame]);
1570 frame.size = [image size];
1571 [view setFrame:frame];
1573 [view setImage:image];
1574 [view wb$updateFrame];
1577 static void $addPerPageViews$(NSArray *lists) {
1578 for (unsigned i(0), e([lists count]); i != e; ++i)
1579 $addPerPageView$(i, [lists objectAtIndex:i]);
1582 MSInstanceMessageHook0(void, SBIconController, updateNumberOfRootIconLists) {
1583 NSArray *&_rootIconLists(MSHookIvar<NSArray *>(self, "_rootIconLists"));
1584 $addPerPageViews$(_rootIconLists);
1588 MSInstanceMessageHook0(void, SBIconContentView, layoutSubviews) {
1591 if (SBIconController *controller = [$SBIconController sharedInstance]) {
1592 UIView *&_dockContainerView(MSHookIvar<UIView *>(controller, "_dockContainerView"));
1593 if (&_dockContainerView != NULL)
1594 [[_dockContainerView superview] bringSubviewToFront:_dockContainerView];
1598 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1599 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1600 $addPerPageViews$([_iconModel iconLists]);
1601 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1604 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1605 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1607 [self setClipsToBounds:NO];
1611 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1612 static bool gssc(false);
1614 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1615 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1618 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1619 [Info_ setObject:[NSNumber numberWithBool:(
1621 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1622 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1623 )] forKey:@"UndockedIconLabels"];
1626 id &_label(MSHookIvar<id>(self, "_label"));
1627 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1630 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1631 [_label setInDock:docked];
1633 _SBIconLabel$setInDock$(self, sel, docked);
1634 [self setNeedsDisplay];
1637 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1638 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1641 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1642 _SBDockIconListView$setFrame$(self, sel, frame);
1645 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1646 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1647 NSString *identifier = [self bundleIdentifier];
1648 NSLocale *locale = [NSLocale currentLocale];
1649 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1651 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1652 NSString *file = table == nil ? @"Localizable" : table;
1653 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1654 NSDictionary *strings;
1655 if ((strings = [Strings_ objectForKey:name]) != nil) {
1656 if (static_cast<id>(strings) != [NSNull null]) strings:
1657 if (NSString *value = [strings objectForKey:key])
1659 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1662 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1663 [Strings_ setObject:[strings autorelease] forKey:name];
1667 [Strings_ setObject:[NSNull null] forKey:name];
1668 return MSOldCall(key, value, table);
1671 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1672 MSClassHook(WebCoreFrameBridge)
1674 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1677 void **core(reinterpret_cast<void **>([node _node]));
1678 if (core == NULL || core[6] == NULL)
1680 return MSOldCall(node, width);
1684 MSInstanceMessage1(void, SBIconLabel, drawRect, CGRect, rect) {
1685 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1688 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1689 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1691 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1693 NSString *style = [NSString stringWithFormat:@""
1694 "font-family: Helvetica; "
1695 "font-weight: bold; "
1697 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1698 ? @"font-size: 12px; "
1699 : @"font-size: 11px; "
1703 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1705 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1707 NSString *custom([Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")]);
1709 $drawLabel$(label, [self bounds], style, custom);
1712 MSInstanceMessage0(CGImageRef, SBIconLabel, buildLabelImage) {
1713 bool docked((MSHookIvar<unsigned>(self, "_inDock") & 0x2) != 0);
1715 WBStringDrawingState labelState = {NULL, 0, @""
1716 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1718 stringDrawingState_ = &labelState;
1721 CGImageRef image(MSOldCall());
1724 stringDrawingState_ = NULL;
1729 MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1730 if ((self = MSOldCall(frame, delegate)) != nil) {
1731 [self setBackgroundColor:[UIColor clearColor]];
1735 MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1736 return SMSBackgrounded_ ? NO : MSOldCall();
1739 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1740 [self wb$setBackgroundColor:[UIColor clearColor]];
1744 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1746 [balloon setBackgroundColor:[UIColor clearColor]];
1749 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1750 MSOldCall([UIColor clearColor]);
1751 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1755 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1756 if ((self = MSOldCall(style, reuse)) != nil) {
1757 [self setBackgroundColor:[UIColor clearColor]];
1758 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1763 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1764 if ((self = MSOldCall(style, reuse)) != nil) {
1765 [self setBackgroundColor:[UIColor clearColor]];
1766 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1770 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1771 if ((self = MSOldCall(style, reuse)) != nil) {
1772 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1773 [_label setBackgroundColor:[UIColor clearColor]];
1777 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1778 MSOldCall(UITableViewCellSeparatorStyleNone);
1781 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1782 if ((self = MSOldCall(frame, style)) != nil) {
1783 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1787 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1790 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1791 if (UIImage *image = $getImage$(path)) {
1792 SMSBackgrounded_ = true;
1794 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1795 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1797 if (&_transcriptTable != NULL)
1798 table = _transcriptTable;
1799 else if (&_transcriptLayer != NULL)
1800 table = _transcriptLayer;
1804 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1805 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1808 [placard insertSubview:background atIndex:0];
1810 [table setBackgroundColor:[UIColor clearColor]];
1811 [placard insertSubview:background belowSubview:table];
1817 // %hook _UIImageWithName() {{{
1818 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1820 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1827 if (_UIPackedImageTableGetIdentifierForName != NULL)
1828 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1829 else if (_UISharedImageNameGetIdentifier != NULL) {
1830 identifier = _UISharedImageNameGetIdentifier(name);
1831 packed = identifier != -1;
1838 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1841 return __UIImageWithName(name);
1843 NSNumber *key([NSNumber numberWithInt:identifier]);
1844 UIImage *image([UIImages_ objectForKey:key]);
1846 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1847 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1848 image = $getImage$(path);
1849 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1853 image = __UIImageWithName(name);
1856 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1857 if (![Manager_ fileExistsAtPath:path])
1858 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1865 // %hook _UIImageWithNameInDomain() {{{
1866 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1867 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1868 UIImage *image([PathImages_ objectForKey:key]);
1870 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1872 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1873 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1874 image = $getImage$(path);
1875 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1876 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1880 // %hook GSFontCreateWithName() {{{
1881 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1883 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1884 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1885 name = [font UTF8String];
1886 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1887 // size *= [scale floatValue];
1888 return _GSFontCreateWithName(name, traits, size);
1892 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1893 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1895 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1897 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1899 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1900 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1902 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1905 NSString *path = [NSString stringWithUTF8String:a1];
1906 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1907 NSString *file = [path substringFromIndex:31];
1908 for (NSString *theme in Themes_) {
1909 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1910 if ([Manager_ fileExistsAtPath:path]) {
1911 strcpy(a1, [path UTF8String]);
1920 static void ChangeWallpaper(
1921 CFNotificationCenterRef center,
1925 CFDictionaryRef info
1928 NSLog(@"WB:Debug:ChangeWallpaper!");
1931 if (WallpaperFile_ != nil) {
1932 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1934 image = [image autorelease];
1937 if (WallpaperImage_ != nil)
1938 [WallpaperImage_ setImage:image];
1939 if (WallpaperPage_ != nil)
1940 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1944 #define WBRename(name, sel, imp) \
1945 MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp, &_ ## name ## $ ## imp)
1947 template <typename Type_>
1948 static void msset(Type_ &function, MSImageRef image, const char *name) {
1949 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1952 template <typename Type_>
1953 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1954 struct nlist &name(nl[index]);
1955 uintptr_t value(name.n_value);
1956 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1957 value |= 0x00000001;
1958 function = reinterpret_cast<Type_>(value);
1961 template <typename Type_>
1962 static void dlset(Type_ &function, const char *name) {
1963 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1966 // %hook CGImageReadCreateWithFile() {{{
1967 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1969 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1970 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1971 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1976 MSHook(void *, CGImageSourceCreateWithFile, NSString *path, NSDictionary *options) {
1978 NSLog(@"WB:Debug: CGImageSourceCreateWithFile(%@, %@)", path, options);
1979 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1980 void *value(_CGImageSourceCreateWithFile([path wb$themedPath], options));
1985 MSHook(void *, CGImageSourceCreateWithURL, NSURL *url, NSDictionary *options) {
1987 NSLog(@"WB:Debug: CGImageSourceCreateWithURL(%@, %@)", url, options);
1988 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1989 if ([url isFileURL])
1990 url = [NSURL fileURLWithPath:[[url path] wb$themedPath]];
1991 void *value(_CGImageSourceCreateWithURL(url, options));
1997 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
1998 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1999 if (style == nil || [style length] == 0)
2000 style = @"font-family: Helvetica; font-size: 12px";
2001 //NSLog(@"XXX:drawP(%@)", [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
2002 return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
2005 static void NSString$drawInRect$withStyle$(NSString *self, SEL _cmd, CGRect rect, NSString *style) {
2006 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
2007 if (style == nil || [style length] == 0)
2008 style = @"font-family: Helvetica; font-size: 12px";
2009 //NSLog(@"XXX:drawR(%@)", [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
2010 return [[WBMarkup sharedMarkup] drawString:self inRect:rect withStyle:style];
2013 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
2014 if (style == nil || [style length] == 0)
2015 style = @"font-family: Helvetica; font-size: 12px";
2016 //NSLog(@"XXX:size(%@)", [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
2017 return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width];
2020 static void SBInitialize() {
2022 WBRename(SBApplication, pathForIcon, pathForIcon);
2023 WBRename(SBApplicationIcon, icon, icon);
2024 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
2027 WBRename(SBBookmarkIcon, icon, icon);
2028 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
2029 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
2030 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
2031 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
2033 WBRename(SBWidgetApplicationIcon, icon, icon);
2035 WBRename(SBDockIconListView, setFrame:, setFrame$);
2036 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
2038 if (kCFCoreFoundationVersionNumber < 600 || SummerBoard_)
2039 WBRename(SBIconLabel, drawRect:, drawRect$);
2041 WBRename(SBIconLabel, buildLabelImage, buildLabelImage);
2043 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
2044 WBRename(SBIconLabel, setInDock:, setInDock$);
2046 WBRename(SBIconList, didMoveToSuperview, didMoveToSuperview);
2047 WBRename(SBIconList, setFrame:, setFrame$);
2049 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
2050 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
2051 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
2052 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
2054 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
2055 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
2056 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
2058 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
2060 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
2061 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
2062 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
2063 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
2064 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
2065 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
2066 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
2067 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
2068 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
2071 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
2075 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2077 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
2078 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
2080 Manager_ = [[NSFileManager defaultManager] retain];
2081 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
2083 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
2085 // Load Settings.plist {{{
2086 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
2087 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
2088 SummerBoard_ = [value boolValue];
2090 SummerBoard_ = true;
2092 if (NSNumber *value = [settings objectForKey:@"Debug"])
2093 Debug_ = [value boolValue];
2094 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
2095 UIDebug_ = [value boolValue];
2097 NSArray *themes([settings objectForKey:@"Themes"]);
2099 if (NSString *theme = [settings objectForKey:@"Theme"])
2100 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
2102 [NSNumber numberWithBool:true], @"Active",
2106 for (NSDictionary *theme in themes) {
2107 NSNumber *active([theme objectForKey:@"Active"]);
2108 if (![active boolValue])
2111 NSString *name([theme objectForKey:@"Name"]);
2115 NSString *theme(nil);
2117 #define testForTheme(format...) \
2118 if (theme == nil) { \
2119 NSString *path = [NSString stringWithFormat:format]; \
2120 if ([Manager_ fileExistsAtPath:path]) { \
2121 [Themes_ addObject:path]; \
2126 testForTheme(@"/Library/Themes/%@.theme", name)
2127 testForTheme(@"/Library/Themes/%@", name)
2128 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
2133 // Merge Info.plist {{{
2134 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2136 for (NSString *theme in Themes_)
2137 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
2138 for (NSString *key in [info allKeys])
2139 if ([Info_ objectForKey:key] == nil)
2140 [Info_ setObject:[info objectForKey:key] forKey:key];
2144 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
2145 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
2146 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
2149 // GraphicsServices {{{
2151 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
2155 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
2156 void *(*CGImageReadCreateWithFile)(NSString *, int);
2157 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
2158 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
2160 if (CGImageReadCreateWithFile == NULL) {
2161 void *(*CGImageSourceCreateWithFile)(NSString *, NSDictionary *);
2162 msset(CGImageSourceCreateWithFile, image, "_CGImageSourceCreateWithFile");
2163 MSHookFunction(CGImageSourceCreateWithFile, MSHake(CGImageSourceCreateWithFile));
2165 void *(*CGImageSourceCreateWithURL)(NSURL *, NSDictionary *);
2166 msset(CGImageSourceCreateWithURL, image, "_CGImageSourceCreateWithURL");
2167 MSHookFunction(CGImageSourceCreateWithURL, MSHake(CGImageSourceCreateWithURL));
2173 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
2174 Papered_ = $getTheme$(Wallpapers_) != nil;
2175 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
2177 CFNotificationCenterAddObserver(
2178 CFNotificationCenterGetDarwinNotifyCenter(),
2179 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
2182 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
2183 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
2184 if (MediaPlayer != nil)
2187 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
2188 $MPVideoView = objc_getClass("MPVideoView");
2195 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
2196 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
2197 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v28@0:4{CGRect={CGSize=ff}{CGSize=ff}}8@24");
2198 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
2201 memset(nl, 0, sizeof(nl));
2202 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
2203 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
2204 nl[2].n_un.n_name = (char *) "__UIKitBundle";
2205 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
2206 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
2209 nlset(_UIApplicationImageWithName, nl, 0);
2210 nlset(_UIImageWithNameInDomain, nl, 1);
2211 nlset(_UIKitBundle, nl, 2);
2212 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
2213 nlset(_UISharedImageNameGetIdentifier, nl, 4);
2215 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
2216 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
2217 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
2221 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
2222 NSError *error(nil);
2223 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
2224 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
2226 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);