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)
125 MSClassHook(CKBalloonView)
126 MSClassHook(CKMessageCell)
127 MSClassHook(CKTimestampView)
128 MSClassHook(CKTranscriptCell)
129 MSClassHook(CKTranscriptController)
130 MSClassHook(CKTranscriptHeaderView)
131 MSClassHook(CKTranscriptTableView)
133 MSClassHook(SBApplication)
134 MSClassHook(SBApplicationIcon)
135 MSClassHook(SBAwayView)
136 MSClassHook(SBBookmarkIcon)
137 MSClassHook(SBButtonBar)
138 MSClassHook(SBCalendarApplicationIcon)
139 MSClassHook(SBCalendarIconContentsView)
140 MSClassHook(SBDockIconListView)
142 MSClassHook(SBIconBadge)
143 MSClassHook(SBIconBadgeFactory)
144 MSClassHook(SBIconController)
145 MSClassHook(SBIconLabel)
146 MSClassHook(SBIconList)
147 MSClassHook(SBIconModel)
148 //MSClassHook(SBImageCache)
149 MSClassHook(SBSearchView)
150 MSClassHook(SBSearchTableViewCell)
151 MSClassHook(SBSlidingAlertDisplay)
152 MSClassHook(SBStatusBarContentsView)
153 MSClassHook(SBStatusBarController)
154 MSClassHook(SBStatusBarOperatorNameView)
155 MSClassHook(SBStatusBarTimeView)
156 MSClassHook(SBUIController)
157 MSClassHook(SBWallpaperView)
158 MSClassHook(SBWidgetApplicationIcon)
160 extern "C" void WKSetCurrentGraphicsContext(CGContextRef);
162 __attribute__((__constructor__))
163 static void MSFixClass() {
165 $SBIcon = objc_getClass("SBIconView");
166 if ($CKTranscriptController == nil)
167 $CKTranscriptController = objc_getClass("mSMSMessageTranscriptController");
171 static bool Four_($SBDockIconListView != nil);
173 @interface NSDictionary (WinterBoard)
174 - (UIColor *) wb$colorForKey:(NSString *)key;
175 - (BOOL) wb$boolForKey:(NSString *)key;
178 @implementation NSDictionary (WinterBoard)
180 - (UIColor *) wb$colorForKey:(NSString *)key {
181 NSString *value = [self objectForKey:key];
188 - (BOOL) wb$boolForKey:(NSString *)key {
189 if (NSString *value = [self objectForKey:key])
190 return [value boolValue];
196 static BOOL (*_GSFontGetUseLegacyFontMetrics)();
197 #define $GSFontGetUseLegacyFontMetrics() \
198 (_GSFontGetUseLegacyFontMetrics == NULL ? YES : _GSFontGetUseLegacyFontMetrics())
200 static bool Debug_ = false;
201 static bool UIDebug_ = false;
202 static bool Engineer_ = false;
203 static bool SummerBoard_ = true;
204 static bool SpringBoard_;
206 static UIImage *(*_UIApplicationImageWithName)(NSString *name);
207 static UIImage *(*_UIImageWithNameInDomain)(NSString *name, NSString *domain);
208 static NSBundle *(*_UIKitBundle)();
209 static bool (*_UIPackedImageTableGetIdentifierForName)(NSString *, int *);
210 static int (*_UISharedImageNameGetIdentifier)(NSString *);
212 static NSMutableDictionary *UIImages_ = [[NSMutableDictionary alloc] initWithCapacity:32];
213 static NSMutableDictionary *PathImages_ = [[NSMutableDictionary alloc] initWithCapacity:16];
214 static NSMutableDictionary *Cache_ = [[NSMutableDictionary alloc] initWithCapacity:64];
215 static NSMutableDictionary *Strings_ = [[NSMutableDictionary alloc] initWithCapacity:0];
216 static NSMutableDictionary *Bundles_ = [[NSMutableDictionary alloc] initWithCapacity:2];
218 static NSFileManager *Manager_;
219 static NSMutableArray *Themes_;
221 static NSDictionary *English_;
222 static NSMutableDictionary *Info_;
225 static NSMutableDictionary *Themed_ = [[NSMutableDictionary alloc] initWithCapacity:128];
227 static unsigned Scale_ = 0;
229 static unsigned $getScale$(NSString *path) {
230 NSString *name(path);
232 #define StripName(strip) \
233 if ([name hasSuffix:@ strip]) \
234 name = [name substringWithRange:NSMakeRange(0, [name length] - sizeof(strip) - 1)];
238 StripName("~iphone");
241 return [name hasSuffix:@"@2x"] ? 2 : 1;
244 static NSArray *$useScale$(NSArray *files, bool use = true) {
245 if (use && Scale_ == 0) {
246 UIScreen *screen([UIScreen mainScreen]);
247 if ([screen respondsToSelector:@selector(scale)])
248 Scale_ = [screen scale];
256 NSString *idiom(IsWild_ ? @"ipad" : @"iphone");
258 NSMutableArray *scaled([NSMutableArray arrayWithCapacity:([files count] * 4)]);
260 for (NSString *file in files) {
261 NSString *base([file stringByDeletingPathExtension]);
262 NSString *extension([file pathExtension]);
266 [scaled addObject:[NSString stringWithFormat:@"%@@2x~%@.%@", base, idiom, extension]];
268 [scaled addObject:[NSString stringWithFormat:@"%@@2x.%@", base, extension]];
271 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
273 // if (!IsWild_) <- support old themes
274 [scaled addObject:file];
275 } else if ([base hasSuffix: @"@2x"]) {
276 [scaled addObject:[NSString stringWithFormat:@"%@~iphone.%@", base, extension]];
277 [scaled addObject:file];
279 // XXX: this actually can't be used, as the person loading the file doesn't realize that the @2x changed
280 /*NSString *rest([base substringWithRange:NSMakeRange(0, [base length] - 3)]);
281 [scaled addObject:[NSString stringWithFormat:@"%@~iphone.%@", rest, extension]];
282 [scaled addObject:[rest stringByAppendingPathExtension:extension]];*/
284 // XXX: this code isn't really complete
286 [scaled addObject:file];
288 if ([base hasSuffix:@"~iphone"])
289 [scaled addObject:[[base substringWithRange:NSMakeRange(0, [base length] - 7)] stringByAppendingPathExtension:extension]];
296 static NSString *$getTheme$(NSArray *files, NSArray *themes = Themes_) {
297 // XXX: this is not reasonable; OMG
300 @synchronized (Themed_) {
301 if (NSString *path = [Themed_ objectForKey:key])
302 return reinterpret_cast<id>(path) == [NSNull null] ? nil : path;
306 NSLog(@"WB:Debug: %@", [files description]);
310 for (NSString *theme in Themes_)
311 for (NSString *file in files) {
312 path = [NSString stringWithFormat:@"%@/%@", theme, file];
313 if ([Manager_ fileExistsAtPath:path])
320 @synchronized (Themed_) {
321 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:key];
327 // $pathForFile$inBundle$() {{{
328 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool ui) {
329 NSString *identifier = [bundle bundleIdentifier];
330 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
332 if (identifier != nil)
333 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
334 if (NSString *folder = [[bundle bundlePath] lastPathComponent]) {
335 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
336 NSString *base([folder stringByDeletingPathExtension]);
337 if ([base hasSuffix:@"~iphone"])
338 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 7)], [folder pathExtension], file]];
341 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
343 #define remapResourceName(oldname, newname) \
344 else if ([file isEqualToString:(oldname)]) \
345 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
347 bool summer(SpringBoard_ && SummerBoard_);
349 if (identifier == nil);
350 else if ([identifier isEqualToString:@"com.apple.chatkit"])
351 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
352 else if ([identifier isEqualToString:@"com.apple.calculator"])
353 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
355 remapResourceName(@"FSO_BG.png", @"StatusBar")
356 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
357 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
359 [names addObject:[NSString stringWithFormat:@"Fallback/%@", file]];
361 if (NSString *path = $getTheme$($useScale$(names, ui)))
368 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
369 NSString *identifier = [self bundleIdentifier];
370 NSString *path = [self path];
371 NSString *folder = [path lastPathComponent];
372 NSString *dname = [self displayName];
373 NSString *didentifier = [self displayIdentifier];
376 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
378 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
380 /* XXX: I might need to keep this for backwards compatibility
381 if (identifier != nil)
382 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
384 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
386 #define testForIcon(Name) \
387 if (NSString *name = Name) \
388 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
390 if (![didentifier isEqualToString:identifier])
391 testForIcon(didentifier);
393 testForIcon(identifier);
396 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
399 if (didentifier != nil) {
400 testForIcon([English_ objectForKey:didentifier]);
402 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
403 if ([parts count] != 1)
404 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
405 testForIcon([english objectForKey:[parts lastObject]]);
408 if (NSString *path = $getTheme$(names))
414 // -[NSBundle wb$bundleWithFile] {{{
415 @interface NSBundle (WinterBoard)
416 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
419 @implementation NSBundle (WinterBoard)
421 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
422 path = [path stringByDeletingLastPathComponent];
423 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
426 NSBundle *bundle([Bundles_ objectForKey:path]);
427 if (reinterpret_cast<id>(bundle) == [NSNull null])
429 else if (bundle == nil) {
430 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
431 bundle = [NSBundle bundleWithPath:path];
433 bundle = [NSBundle wb$bundleWithFile:path];
435 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
436 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
444 // -[NSString wb$themedPath] {{{
445 @interface NSString (WinterBoard)
446 - (NSString *) wb$themedPath;
449 @implementation NSString (WinterBoard)
451 - (NSString *) wb$themedPath {
452 if ([self hasPrefix:@"/Library/Themes/"])
456 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
458 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
459 NSString *file([self stringByResolvingSymlinksInPath]);
460 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
461 if ([file hasPrefix:prefix]) {
462 NSUInteger length([prefix length]);
463 if (length != [file length])
464 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
475 void WBLogRect(const char *tag, struct CGRect rect) {
476 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
479 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
480 CGRect frame([view frame]);
481 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]);
483 for (UIView *child in [view subviews])
484 WBLogHierarchy(child, index++, indent + 1);
487 UIImage *$cacheForImage$(UIImage *image) {
488 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
489 CGRect rect = {CGPointMake(1, 1), [image size]};
490 CGSize size = {rect.size.width + 2, rect.size.height + 2};
492 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
493 CGColorSpaceRelease(space);
495 CGContextDrawImage(context, rect, [image CGImage]);
496 CGImageRef ref(CGBitmapContextCreateImage(context));
497 CGContextRelease(context);
499 UIImage *cache([UIImage imageWithCGImage:ref]);
505 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
506 //if ([name isEqualToString:@"icons"]) return nil;
507 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
510 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
511 NSString *key([icon displayIdentifier]);
513 if (UIImage *image = [icon icon]) {
514 CGSize size = [image size];
515 if (size.width != 59 || size.height != 60) {
516 UIImage *cache($cacheForImage$(image));
517 [Cache_ setObject:cache forKey:key];
522 _SBIconModel$cacheImageForIcon$(self, sel, icon);
525 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
526 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
527 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
529 NSString *key([icon displayIdentifier]);
531 if (UIImage *image = [icon icon]) {
532 CGSize size = [image size];
533 if (size.width != 59 || size.height != 60) {
534 UIImage *cache($cacheForImage$(image));
535 [Cache_ setObject:cache forKey:key];
541 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
542 NSString *key([icon displayIdentifier]);
543 if (UIImage *image = [Cache_ objectForKey:key])
546 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
549 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
551 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
552 NSString *key([icon displayIdentifier]);
553 if (UIImage *image = [Cache_ objectForKey:key])
556 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
559 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
560 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
561 [self setBackgroundColor:[UIColor clearColor]];
562 for (UIView *child in [self subviews])
563 [child setBackgroundColor:[UIColor clearColor]];
567 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
568 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
569 [self setBackgroundColor:[UIColor clearColor]];
573 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
574 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
575 float inset([self edgeInset]);
576 [[UIColor clearColor] set];
577 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
578 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
581 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
582 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
583 if (NSString *path = $pathForIcon$([self application]))
584 return [UIImage imageWithContentsOfFile:path];
585 return _SBApplicationIcon$icon(self, sel);
588 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
590 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
591 if (IsWild_ && false) // XXX: delete this code, it should not be supported
592 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
593 return [UIImage imageWithContentsOfFile:path72];
594 if (NSString *path = $pathForIcon$([self application]))
595 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
597 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
598 width = [$SBIcon defaultIconImageSize].width;
601 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
604 return _SBApplicationIcon$generateIconImage$(self, sel, type);
607 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
609 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
610 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
611 return [UIImage imageWithContentsOfFile:path];
612 return _SBWidgetApplicationIcon$icon(self, sel);
615 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
617 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
618 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
619 return [UIImage imageWithContentsOfFile:path];
620 return _SBBookmarkIcon$icon(self, sel);
623 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
624 if (NSString *path = $pathForIcon$(self))
626 return _SBApplication$pathForIcon(self, sel);
629 static UIImage *CachedImageAtPath(NSString *path) {
630 path = [path stringByResolvingSymlinksInPath];
631 UIImage *image = [PathImages_ objectForKey:path];
633 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
634 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
636 image = [image autorelease];
637 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
641 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
642 NSBundle *bundle = [NSBundle mainBundle];
644 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
645 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
646 return CachedImageAtPath(path);
647 return __UIApplicationImageWithName(name);
650 #define WBDelegate(delegate) \
651 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
653 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
654 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
656 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
660 - (void) forwardInvocation:(NSInvocation*)inv { \
661 SEL sel = [inv selector]; \
662 if ([delegate respondsToSelector:sel]) \
663 [inv invokeWithTarget:delegate]; \
665 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
668 // %hook -[NSBundle pathForResource:ofType:] {{{
669 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
670 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
672 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
673 if (NSString *path = $pathForFile$inBundle$(file, self, false))
675 return MSOldCall(resource, type);
679 static struct WBStringDrawingState {
680 WBStringDrawingState *next_;
684 } *stringDrawingState_;
686 MSInstanceMessageHook4(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode, CGPoint, point, float, width, UIFont *, font, int, mode) {
687 WBStringDrawingState *state(stringDrawingState_);
689 return MSOldCall(point, width, font, mode);
691 if (--state->count_ == 0)
692 stringDrawingState_ = state->next_;
693 if (state->info_ == nil)
694 return MSOldCall(point, width, font, mode);
696 NSString *info([Info_ objectForKey:state->info_]);
698 return MSOldCall(point, width, font, mode);
700 NSString *base(state->base_ ?: @"");
701 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]];
705 MSInstanceMessageHook2(CGSize, NSString, drawAtPoint,withFont, CGPoint, point, UIFont *, font) {
706 WBStringDrawingState *state(stringDrawingState_);
708 return MSOldCall(point, font);
710 if (--state->count_ == 0)
711 stringDrawingState_ = state->next_;
712 if (state->info_ == nil)
713 return MSOldCall(point, font);
715 NSString *info([Info_ objectForKey:state->info_]);
717 return MSOldCall(point, font);
719 NSString *base(state->base_ ?: @"");
720 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]];
724 MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) {
725 WBStringDrawingState *state(stringDrawingState_);
727 return MSOldCall(font);
729 if (--state->count_ == 0)
730 stringDrawingState_ = state->next_;
731 if (state->info_ == nil)
732 return MSOldCall(font);
734 NSString *info([Info_ objectForKey:state->info_]);
736 return MSOldCall(font);
738 NSString *base(state->base_ ?: @"");
739 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info] forWidth:65535];
742 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
743 WBStringDrawingState badgeState = {NULL, 1, @""
747 stringDrawingState_ = &badgeState;
749 UIImage *image(MSOldCall(text));
751 stringDrawingState_ = NULL;
755 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
756 WBStringDrawingState dayState = {NULL, 2, @""
758 // XXX: this is only correct on an iPod dock
759 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
760 , @"CalendarIconDayStyle"};
762 WBStringDrawingState sizeState = {&dayState, 7, nil, nil};
764 WBStringDrawingState dateState = {&sizeState, 2, @""
766 , @"CalendarIconDateStyle"};
768 stringDrawingState_ = &dateState;
770 UIImage *image(MSOldCall(type));
772 stringDrawingState_ = NULL;
776 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
777 NSBundle *bundle([NSBundle mainBundle]);
779 CFLocaleRef locale(CFLocaleCopyCurrent());
780 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
783 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
785 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
786 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
787 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
788 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
792 CFRelease(formatter);
794 NSString *datestyle([@""
795 "font-family: Helvetica; "
796 "font-weight: bold; "
799 "" stringByAppendingString:(IsWild_
800 ? @"font-size: 54px; "
801 : @"font-size: 39px; "
804 NSString *daystyle([@""
805 "font-family: Helvetica; "
806 "font-weight: bold; "
808 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
809 "" stringByAppendingString:(IsWild_
810 ? @"font-size: 11px; "
811 : @"font-size: 9px; "
814 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
815 datestyle = [datestyle stringByAppendingString:style];
816 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
817 daystyle = [daystyle stringByAppendingString:style];
819 float width([self bounds].size.width);
821 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
822 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
824 unsigned base0(IsWild_ ? 89 : 70);
825 if ($GSFontGetUseLegacyFontMetrics())
827 unsigned base1(IsWild_ ? 18 : 16);
834 [(NSString *)date drawAtPoint:CGPointMake(
835 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
836 ) withStyle:datestyle];
838 [(NSString *)day drawAtPoint:CGPointMake(
839 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
840 ) withStyle:daystyle];
846 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
847 void $setBarStyle$_(NSString *name, int &style) {
849 NSLog(@"WB:Debug:%@Style:%d", name, style);
850 NSNumber *number = nil;
852 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
854 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
856 style = [number intValue];
858 NSLog(@"WB:Debug:%@Style=%d", name, style);
862 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
863 $setBarStyle$_(@"Toolbar", style);
864 return MSOldCall(style);
867 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
868 $setBarStyle$_(@"NavigationBar", style);
869 return MSOldCall(style);
873 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
874 [[self superview] setBackgroundColor:[UIColor clearColor]];
875 _SBButtonBar$didMoveToSuperview(self, sel);
878 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
879 [[self superview] setBackgroundColor:[UIColor clearColor]];
880 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
883 static NSArray *Wallpapers_;
884 static bool Papered_;
886 static bool SMSBackgrounded_;
887 static NSString *WallpaperFile_;
888 static UIImageView *WallpaperImage_;
889 static UIWebDocumentView *WallpaperPage_;
890 static NSURL *WallpaperURL_;
892 #define _release(object) \
893 do if (object != nil) { \
898 static UIImage *$getImage$(NSString *path) {
899 UIImage *image([UIImage imageWithContentsOfFile:path]);
901 unsigned scale($getScale$(path));
902 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
903 [image setScale:scale];
908 static UIImage *$getDefaultDesktopImage$() {
909 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
910 return $getImage$(path);
914 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
915 return $getDefaultDesktopImage$() ?: MSOldCall();
918 MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
919 return $getDefaultDesktopImage$() ?: MSOldCall();
922 MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
923 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
924 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
925 if (UIImage *image = $getDefaultDesktopImage$()) {
926 [self setImage:image];
936 // %hook -[SBUIController init] {{{
937 MSInstanceMessageHook0(id, SBUIController, init) {
942 NSString *paper($getTheme$(Wallpapers_));
944 paper = [paper stringByDeletingLastPathComponent];
948 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
949 char *machine = new char[size];
951 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
952 perror("sysctlbyname(\"hw.machine\", ?)");
957 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
961 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
964 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
965 if (&_wallpaperView != NULL) {
966 [_wallpaperView removeFromSuperview];
967 [_wallpaperView release];
968 _wallpaperView = nil;
972 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
973 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
976 if (&_contentLayer != NULL)
977 player = &_contentLayer;
978 else if (&_contentView != NULL)
979 player = &_contentView;
982 UIView *layer(player == NULL ? nil : *player);
984 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
985 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
986 [window setContentView:content];
988 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
989 [window setBackgroundColor:[_window backgroundColor]];
990 [_window setBackgroundColor:[UIColor clearColor]];
992 [window setLevel:-1000];
993 [window setHidden:NO];
995 /*if (player != NULL)
998 [content setBackgroundColor:[layer backgroundColor]];
999 [layer setBackgroundColor:[UIColor clearColor]];
1002 if (!SummerBoard_ || !IsWild_)
1005 CGRect bounds([content bounds]);
1006 bounds.origin.y = -30;
1007 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
1008 [content addSubview:indirect];
1009 [indirect zoomToScale:2.4];
1012 _release(WallpaperFile_);
1013 _release(WallpaperImage_);
1014 _release(WallpaperPage_);
1015 _release(WallpaperURL_);
1018 NSArray *themes([NSArray arrayWithObject:paper]);
1020 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1024 static AVController *controller_(nil);
1025 if (controller_ == nil) {
1026 AVQueue *queue([AVQueue avQueue]);
1027 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1030 AVQueue *queue([controller_ queue]);
1032 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1033 [controller_ setLayer:[video _layer]];
1035 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1036 [queue appendItem:item error:&error];
1038 [controller_ play:&error];
1039 #elif UseMPMoviePlayerController
1040 NSURL *url([NSURL fileURLWithPath:path]);
1041 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1042 controller.movieControlMode = MPMovieControlModeHidden;
1045 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1046 [video setMovieWithPath:path];
1047 [video setRepeatMode:1];
1048 [video setRepeatGap:-1];
1049 [video playFromBeginning];;
1052 [indirect addSubview:video];
1055 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1056 if (UIImage *image = $getImage$(path)) {
1057 WallpaperFile_ = [path retain];
1058 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1059 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1060 [WallpaperImage_ setAlpha:[number floatValue]];
1061 [indirect addSubview:WallpaperImage_];
1065 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1066 CGRect bounds = [indirect bounds];
1068 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1069 [view setAutoresizes:true];
1071 WallpaperPage_ = [view retain];
1072 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1074 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1076 [view setBackgroundColor:[UIColor clearColor]];
1077 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1078 [view setDrawsBackground:NO];
1079 [[view webView] setDrawsBackground:NO];
1081 [indirect addSubview:view];
1085 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1086 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1087 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1088 if ([Manager_ fileExistsAtPath:html]) {
1089 CGRect bounds = [indirect bounds];
1091 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1092 [view setAutoresizes:true];
1094 NSURL *url = [NSURL fileURLWithPath:html];
1095 [view loadRequest:[NSURLRequest requestWithURL:url]];
1097 [view setBackgroundColor:[UIColor clearColor]];
1098 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1099 [view setDrawsBackground:NO];
1100 [[view webView] setDrawsBackground:NO];
1102 [indirect addSubview:view];
1110 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1111 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1112 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1114 if (path != nil && _backgroundView != nil)
1117 _SBAwayView$updateDesktopImage$(self, sel, image);
1120 CGRect bounds = [self bounds];
1122 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1123 [view setAutoresizes:true];
1125 if (WallpaperPage_ != nil)
1126 [WallpaperPage_ release];
1127 WallpaperPage_ = [view retain];
1129 if (WallpaperURL_ != nil)
1130 [WallpaperURL_ release];
1131 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1133 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1135 [[view webView] setDrawsBackground:false];
1136 [view setBackgroundColor:[UIColor clearColor]];
1138 [self insertSubview:view aboveSubview:_backgroundView];
1142 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1143 extern "C" CGColorRef CGGStateGetFillColor(void *);
1144 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1145 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1147 /* WBTimeLabel {{{ */
1148 @interface WBTimeLabel : NSProxy {
1150 _transient SBStatusBarTimeView *view_;
1153 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1157 @implementation WBTimeLabel
1164 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1165 time_ = [time retain];
1170 - (NSString *) description {
1176 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1177 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1178 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1180 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1181 "font-family: Helvetica; "
1182 "font-weight: bold; "
1185 "%@", _mode ? @"white" : @"black", custom]];
1190 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1195 /* WBBadgeLabel {{{ */
1196 @interface WBBadgeLabel : NSProxy {
1200 - (id) initWithBadge:(NSString *)badge;
1201 - (NSString *) description;
1205 @implementation WBBadgeLabel
1212 - (id) initWithBadge:(NSString *)badge {
1213 badge_ = [badge retain];
1217 - (NSString *) description {
1218 return [badge_ description];
1223 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1224 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1225 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1226 "font-family: Helvetica; "
1227 "font-weight: bold; "
1235 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1242 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1243 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1244 alpha = [number floatValue];
1245 return MSOldCall(alpha);
1248 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1249 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1250 alpha = [number floatValue];
1251 return MSOldCall(alpha);
1254 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1255 if ((self = MSOldCall()) != nil) {
1256 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1257 // XXX: note: this is overridden above, which is silly
1258 float alpha([number floatValue]);
1259 [self setIconImageAlpha:alpha];
1260 [self setIconLabelAlpha:alpha];
1265 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1266 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1267 alpha = [number floatValue];
1268 return MSOldCall(alpha);
1272 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1273 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1274 id &_badge(MSHookIvar<id>(self, "_badge"));
1276 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1281 void SBStatusBarController$setStatusBarMode(int &mode) {
1283 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1284 if (mode < 100) // 104:hidden 105:glowing
1285 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1286 mode = [number intValue];
1289 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1290 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1291 SBStatusBarController$setStatusBarMode(mode);
1292 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1295 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1296 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1297 SBStatusBarController$setStatusBarMode(mode);
1298 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1301 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) {
1302 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1303 SBStatusBarController$setStatusBarMode(mode);
1304 //NSLog(@"mode=%u", mode);
1305 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1308 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1309 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1310 mode = [number intValue];
1311 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1314 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1315 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1317 NSLog(@"operatorNameStyle= %@", style);
1318 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1319 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1323 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1325 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1326 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1329 // XXX: replace this with [SBStatusBarTimeView tile]
1330 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1331 id &_time(MSHookIvar<id>(self, "_time"));
1332 if (_time != nil && [_time class] != [WBTimeLabel class])
1333 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1334 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1337 @interface UIView (WinterBoard)
1338 - (bool) wb$isWBImageView;
1339 - (void) wb$logHierarchy;
1340 - (void) wb$setBackgroundColor:(UIColor *)color;
1343 @implementation UIView (WinterBoard)
1345 - (bool) wb$isWBImageView {
1349 - (void) wb$logHierarchy {
1350 WBLogHierarchy(self);
1353 - (void) wb$setBackgroundColor:(UIColor *)color {
1354 [self setBackgroundColor:color];
1355 for (UIView *child in [self subviews])
1356 [child wb$setBackgroundColor:color];
1361 @interface WBImageView : UIImageView {
1364 - (bool) wb$isWBImageView;
1365 - (void) wb$updateFrame;
1368 @implementation WBImageView
1370 - (bool) wb$isWBImageView {
1374 - (void) wb$updateFrame {
1375 CGRect frame([self frame]);
1378 for (UIView *view(self); ; ) {
1379 view = [view superview];
1382 frame.origin.y -= [view frame].origin.y;
1385 [self setFrame:frame];
1390 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1391 NSArray *subviews([self subviews]);
1392 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1393 if (view != nil && [view wb$isWBImageView])
1394 [view wb$updateFrame];
1395 _SBIconList$setFrame$(self, sel, frame);
1398 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1399 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1400 NSArray *lists([_iconModel iconLists]);
1402 for (unsigned i(0), e([lists count]); i != e; ++i)
1403 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]])) {
1404 SBIconList *list([lists objectAtIndex:i]);
1405 NSArray *subviews([list subviews]);
1407 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1408 if (view == nil || ![view wb$isWBImageView]) {
1409 view = [[[WBImageView alloc] init] autorelease];
1410 [list insertSubview:view atIndex:0];
1413 UIImage *image([UIImage imageWithContentsOfFile:path]);
1415 CGRect frame([view frame]);
1416 frame.size = [image size];
1417 [view setFrame:frame];
1419 [view setImage:image];
1420 [view wb$updateFrame];
1423 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1426 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1427 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1429 [self setClipsToBounds:NO];
1433 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1434 static bool gssc(false);
1436 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1437 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1440 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1441 [Info_ setObject:[NSNumber numberWithBool:(
1443 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1444 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1445 )] forKey:@"UndockedIconLabels"];
1448 id &_label(MSHookIvar<id>(self, "_label"));
1449 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1452 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1453 [_label setInDock:docked];
1455 _SBIconLabel$setInDock$(self, sel, docked);
1456 [self setNeedsDisplay];
1459 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1460 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1463 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1464 _SBDockIconListView$setFrame$(self, sel, frame);
1467 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1468 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1469 NSString *identifier = [self bundleIdentifier];
1470 NSLocale *locale = [NSLocale currentLocale];
1471 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1473 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1474 NSString *file = table == nil ? @"Localizable" : table;
1475 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1476 NSDictionary *strings;
1477 if ((strings = [Strings_ objectForKey:name]) != nil) {
1478 if (static_cast<id>(strings) != [NSNull null]) strings:
1479 if (NSString *value = [strings objectForKey:key])
1481 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1484 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1485 [Strings_ setObject:[strings autorelease] forKey:name];
1489 [Strings_ setObject:[NSNull null] forKey:name];
1490 return MSOldCall(key, value, table);
1493 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1494 MSClassHook(WebCoreFrameBridge)
1496 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1499 void **core(reinterpret_cast<void **>([node _node]));
1500 if (core == NULL || core[6] == NULL)
1502 return MSOldCall(node, width);
1506 MSInstanceMessageHook1(void, SBIconLabel, drawRect, CGRect, rect) {
1507 CGRect bounds = [self bounds];
1509 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1512 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1513 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1515 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1517 NSString *style = [NSString stringWithFormat:@""
1518 "font-family: Helvetica; "
1519 "font-weight: bold; "
1521 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1522 ? @"font-size: 12px; "
1523 : @"font-size: 11px; "
1527 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1529 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1531 bool ellipsis(false);
1532 float max = [self frame].size.width - 11, width;
1534 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
1537 size_t length([label length]);
1538 float spacing((width - max) / (length - 1));
1540 if (spacing > 1.25) {
1542 label = [label substringToIndex:(length - 1)];
1546 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
1550 label = [label stringByAppendingString:@"..."];
1552 if (NSString *custom = [Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")])
1553 style = [style stringByAppendingString:custom];
1555 CGSize size = [label sizeWithStyle:style forWidth:bounds.size.width];
1556 [label drawAtPoint:CGPointMake((bounds.size.width - size.width) / 2, 0) withStyle:style];
1560 MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1561 if ((self = MSOldCall(frame, delegate)) != nil) {
1562 [self setBackgroundColor:[UIColor clearColor]];
1566 MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1567 return SMSBackgrounded_ ? NO : MSOldCall();
1570 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1571 [self wb$setBackgroundColor:[UIColor clearColor]];
1575 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1577 [balloon setBackgroundColor:[UIColor clearColor]];
1580 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1581 MSOldCall([UIColor clearColor]);
1582 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1586 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1587 if ((self = MSOldCall(style, reuse)) != nil) {
1588 [self setBackgroundColor:[UIColor clearColor]];
1589 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1594 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1595 if ((self = MSOldCall(style, reuse)) != nil) {
1596 [self setBackgroundColor:[UIColor clearColor]];
1597 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1601 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1602 if ((self = MSOldCall(style, reuse)) != nil) {
1603 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1604 [_label setBackgroundColor:[UIColor clearColor]];
1608 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1609 MSOldCall(UITableViewCellSeparatorStyleNone);
1612 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1613 if ((self = MSOldCall(frame, style)) != nil) {
1614 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1618 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1621 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1622 if (UIImage *image = $getImage$(path)) {
1623 SMSBackgrounded_ = true;
1625 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1626 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1628 if (&_transcriptTable != NULL)
1629 table = _transcriptTable;
1630 else if (&_transcriptLayer != NULL)
1631 table = _transcriptLayer;
1635 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1636 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1639 [placard insertSubview:background atIndex:0];
1641 [table setBackgroundColor:[UIColor clearColor]];
1642 [placard insertSubview:background belowSubview:table];
1648 // %hook _UIImageWithName() {{{
1649 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1651 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1658 if (_UIPackedImageTableGetIdentifierForName != NULL)
1659 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1660 else if (_UISharedImageNameGetIdentifier != NULL) {
1661 identifier = _UISharedImageNameGetIdentifier(name);
1662 packed = identifier != -1;
1669 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1672 return __UIImageWithName(name);
1674 NSNumber *key([NSNumber numberWithInt:identifier]);
1675 UIImage *image([UIImages_ objectForKey:key]);
1677 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1678 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1679 image = $getImage$(path);
1680 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1684 image = __UIImageWithName(name);
1687 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1688 if (![Manager_ fileExistsAtPath:path])
1689 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1696 // %hook _UIImageWithNameInDomain() {{{
1697 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1698 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1699 UIImage *image([PathImages_ objectForKey:key]);
1701 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1703 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1704 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1705 image = $getImage$(path);
1706 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1707 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1711 // %hook GSFontCreateWithName() {{{
1712 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1714 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1715 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1716 name = [font UTF8String];
1717 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1718 // size *= [scale floatValue];
1719 return _GSFontCreateWithName(name, traits, size);
1723 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1724 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1726 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1728 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1730 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1731 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1733 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1736 NSString *path = [NSString stringWithUTF8String:a1];
1737 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1738 NSString *file = [path substringFromIndex:31];
1739 for (NSString *theme in Themes_) {
1740 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1741 if ([Manager_ fileExistsAtPath:path]) {
1742 strcpy(a1, [path UTF8String]);
1751 static void ChangeWallpaper(
1752 CFNotificationCenterRef center,
1756 CFDictionaryRef info
1759 NSLog(@"WB:Debug:ChangeWallpaper!");
1762 if (WallpaperFile_ != nil) {
1763 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1765 image = [image autorelease];
1768 if (WallpaperImage_ != nil)
1769 [WallpaperImage_ setImage:image];
1770 if (WallpaperPage_ != nil)
1771 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1775 #define WBRename(name, sel, imp) \
1776 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
1778 template <typename Type_>
1779 static void msset(Type_ &function, MSImageRef image, const char *name) {
1780 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1783 template <typename Type_>
1784 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1785 struct nlist &name(nl[index]);
1786 uintptr_t value(name.n_value);
1787 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1788 value |= 0x00000001;
1789 function = reinterpret_cast<Type_>(value);
1792 template <typename Type_>
1793 static void dlset(Type_ &function, const char *name) {
1794 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1797 // %hook CGImageReadCreateWithFile() {{{
1798 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1800 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1801 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1802 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1808 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
1809 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1810 if (style == nil || [style length] == 0)
1811 style = @"font-family: Helvetica; font-size: 12px";
1812 return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
1815 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
1816 if (style == nil || [style length] == 0)
1817 style = @"font-family: Helvetica; font-size: 12px";
1818 return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width];
1821 static void SBInitialize() {
1822 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
1823 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
1826 WBRename(SBApplication, pathForIcon, pathForIcon);
1827 WBRename(SBApplicationIcon, icon, icon);
1828 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1831 WBRename(SBBookmarkIcon, icon, icon);
1832 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1833 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1834 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1835 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
1837 WBRename(SBWidgetApplicationIcon, icon, icon);
1839 WBRename(SBDockIconListView, setFrame:, setFrame$);
1840 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
1842 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
1843 WBRename(SBIconLabel, setInDock:, setInDock$);
1845 WBRename(SBIconList, setFrame:, setFrame$);
1847 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
1848 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
1849 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
1850 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
1852 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
1853 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
1854 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
1856 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
1858 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
1859 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
1860 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
1861 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
1862 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
1863 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
1864 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
1865 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
1866 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
1869 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
1873 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1875 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
1876 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
1878 Manager_ = [[NSFileManager defaultManager] retain];
1879 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
1881 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
1883 // Load Settings.plist {{{
1884 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
1885 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
1886 SummerBoard_ = [value boolValue];
1887 if (NSNumber *value = [settings objectForKey:@"Debug"])
1888 Debug_ = [value boolValue];
1889 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
1890 UIDebug_ = [value boolValue];
1892 NSArray *themes([settings objectForKey:@"Themes"]);
1894 if (NSString *theme = [settings objectForKey:@"Theme"])
1895 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
1897 [NSNumber numberWithBool:true], @"Active",
1901 for (NSDictionary *theme in themes) {
1902 NSNumber *active([theme objectForKey:@"Active"]);
1903 if (![active boolValue])
1906 NSString *name([theme objectForKey:@"Name"]);
1910 NSString *theme(nil);
1912 #define testForTheme(format...) \
1913 if (theme == nil) { \
1914 NSString *path = [NSString stringWithFormat:format]; \
1915 if ([Manager_ fileExistsAtPath:path]) { \
1916 [Themes_ addObject:path]; \
1921 testForTheme(@"/Library/Themes/%@.theme", name)
1922 testForTheme(@"/Library/Themes/%@", name)
1923 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
1928 // Merge Info.plist {{{
1929 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1931 for (NSString *theme in Themes_)
1932 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
1933 for (NSString *key in [info allKeys])
1934 if ([Info_ objectForKey:key] == nil)
1935 [Info_ setObject:[info objectForKey:key] forKey:key];
1939 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
1940 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
1941 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
1944 // GraphicsServices {{{
1946 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
1950 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
1951 void *(*CGImageReadCreateWithFile)(NSString *, int);
1952 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
1953 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
1958 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
1959 Papered_ = $getTheme$(Wallpapers_) != nil;
1960 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
1962 CFNotificationCenterAddObserver(
1963 CFNotificationCenterGetDarwinNotifyCenter(),
1964 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
1967 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
1968 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
1969 if (MediaPlayer != nil)
1972 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
1973 $MPVideoView = objc_getClass("MPVideoView");
1980 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
1982 memset(nl, 0, sizeof(nl));
1983 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
1984 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
1985 nl[2].n_un.n_name = (char *) "__UIKitBundle";
1986 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
1987 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
1990 nlset(_UIApplicationImageWithName, nl, 0);
1991 nlset(_UIImageWithNameInDomain, nl, 1);
1992 nlset(_UIKitBundle, nl, 2);
1993 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
1994 nlset(_UISharedImageNameGetIdentifier, nl, 4);
1996 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
1997 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
1998 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
2002 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
2003 NSError *error(nil);
2004 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
2005 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
2007 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);