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 if (NSString *path = $getTheme$($useScale$(names, ui)))
366 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
367 NSString *identifier = [self bundleIdentifier];
368 NSString *path = [self path];
369 NSString *folder = [path lastPathComponent];
370 NSString *dname = [self displayName];
371 NSString *didentifier = [self displayIdentifier];
374 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
376 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
378 /* XXX: I might need to keep this for backwards compatibility
379 if (identifier != nil)
380 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
382 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
384 #define testForIcon(Name) \
385 if (NSString *name = Name) \
386 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
388 if (![didentifier isEqualToString:identifier])
389 testForIcon(didentifier);
391 testForIcon(identifier);
394 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
397 if (didentifier != nil) {
398 testForIcon([English_ objectForKey:didentifier]);
400 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
401 if ([parts count] != 1)
402 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
403 testForIcon([english objectForKey:[parts lastObject]]);
406 if (NSString *path = $getTheme$(names))
412 // -[NSBundle wb$bundleWithFile] {{{
413 @interface NSBundle (WinterBoard)
414 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
417 @implementation NSBundle (WinterBoard)
419 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
420 path = [path stringByDeletingLastPathComponent];
421 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
424 NSBundle *bundle([Bundles_ objectForKey:path]);
425 if (reinterpret_cast<id>(bundle) == [NSNull null])
427 else if (bundle == nil) {
428 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
429 bundle = [NSBundle bundleWithPath:path];
431 bundle = [NSBundle wb$bundleWithFile:path];
433 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
434 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
442 // -[NSString wb$themedPath] {{{
443 @interface NSString (WinterBoard)
444 - (NSString *) wb$themedPath;
447 @implementation NSString (WinterBoard)
449 - (NSString *) wb$themedPath {
450 if ([self hasPrefix:@"/Library/Themes/"])
454 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
456 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
457 NSString *file([self stringByResolvingSymlinksInPath]);
458 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
459 if ([file hasPrefix:prefix]) {
460 NSUInteger length([prefix length]);
461 if (length != [file length])
462 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
473 void WBLogRect(const char *tag, struct CGRect rect) {
474 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
477 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
478 CGRect frame([view frame]);
479 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]);
481 for (UIView *child in [view subviews])
482 WBLogHierarchy(child, index++, indent + 1);
485 UIImage *$cacheForImage$(UIImage *image) {
486 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
487 CGRect rect = {CGPointMake(1, 1), [image size]};
488 CGSize size = {rect.size.width + 2, rect.size.height + 2};
490 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
491 CGColorSpaceRelease(space);
493 CGContextDrawImage(context, rect, [image CGImage]);
494 CGImageRef ref(CGBitmapContextCreateImage(context));
495 CGContextRelease(context);
497 UIImage *cache([UIImage imageWithCGImage:ref]);
503 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
504 //if ([name isEqualToString:@"icons"]) return nil;
505 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
508 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
509 NSString *key([icon displayIdentifier]);
511 if (UIImage *image = [icon icon]) {
512 CGSize size = [image size];
513 if (size.width != 59 || size.height != 60) {
514 UIImage *cache($cacheForImage$(image));
515 [Cache_ setObject:cache forKey:key];
520 _SBIconModel$cacheImageForIcon$(self, sel, icon);
523 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
524 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
525 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
527 NSString *key([icon displayIdentifier]);
529 if (UIImage *image = [icon icon]) {
530 CGSize size = [image size];
531 if (size.width != 59 || size.height != 60) {
532 UIImage *cache($cacheForImage$(image));
533 [Cache_ setObject:cache forKey:key];
539 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
540 NSString *key([icon displayIdentifier]);
541 if (UIImage *image = [Cache_ objectForKey:key])
544 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
547 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
549 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
550 NSString *key([icon displayIdentifier]);
551 if (UIImage *image = [Cache_ objectForKey:key])
554 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
557 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
558 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
559 [self setBackgroundColor:[UIColor clearColor]];
560 for (UIView *child in [self subviews])
561 [child setBackgroundColor:[UIColor clearColor]];
565 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
566 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
567 [self setBackgroundColor:[UIColor clearColor]];
571 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
572 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
573 float inset([self edgeInset]);
574 [[UIColor clearColor] set];
575 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
576 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
579 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
580 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
581 if (NSString *path = $pathForIcon$([self application]))
582 return [UIImage imageWithContentsOfFile:path];
583 return _SBApplicationIcon$icon(self, sel);
586 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
588 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
589 if (IsWild_ && false) // XXX: delete this code, it should not be supported
590 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
591 return [UIImage imageWithContentsOfFile:path72];
592 if (NSString *path = $pathForIcon$([self application]))
593 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
595 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
596 width = [$SBIcon defaultIconImageSize].width;
599 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
602 return _SBApplicationIcon$generateIconImage$(self, sel, type);
605 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
607 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
608 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
609 return [UIImage imageWithContentsOfFile:path];
610 return _SBWidgetApplicationIcon$icon(self, sel);
613 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
615 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
616 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
617 return [UIImage imageWithContentsOfFile:path];
618 return _SBBookmarkIcon$icon(self, sel);
621 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
622 if (NSString *path = $pathForIcon$(self))
624 return _SBApplication$pathForIcon(self, sel);
627 static UIImage *CachedImageAtPath(NSString *path) {
628 path = [path stringByResolvingSymlinksInPath];
629 UIImage *image = [PathImages_ objectForKey:path];
631 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
632 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
634 image = [image autorelease];
635 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
639 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
640 NSBundle *bundle = [NSBundle mainBundle];
642 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
643 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
644 return CachedImageAtPath(path);
645 return __UIApplicationImageWithName(name);
648 #define WBDelegate(delegate) \
649 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
651 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
652 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
654 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
658 - (void) forwardInvocation:(NSInvocation*)inv { \
659 SEL sel = [inv selector]; \
660 if ([delegate respondsToSelector:sel]) \
661 [inv invokeWithTarget:delegate]; \
663 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
666 // %hook -[NSBundle pathForResource:ofType:] {{{
667 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
668 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
670 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
671 if (NSString *path = $pathForFile$inBundle$(file, self, false))
673 return MSOldCall(resource, type);
677 static struct WBStringDrawingState {
678 WBStringDrawingState *next_;
682 } *stringDrawingState_;
684 MSInstanceMessageHook4(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode, CGPoint, point, float, width, UIFont *, font, int, mode) {
685 WBStringDrawingState *state(stringDrawingState_);
687 return MSOldCall(point, width, font, mode);
689 if (--state->count_ == 0)
690 stringDrawingState_ = state->next_;
691 if (state->info_ == nil)
692 return MSOldCall(point, width, font, mode);
694 NSString *info([Info_ objectForKey:state->info_]);
696 return MSOldCall(point, width, font, mode);
698 NSString *base(state->base_ ?: @"");
699 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]];
703 MSInstanceMessageHook2(CGSize, NSString, drawAtPoint,withFont, CGPoint, point, UIFont *, font) {
704 WBStringDrawingState *state(stringDrawingState_);
706 return MSOldCall(point, font);
708 if (--state->count_ == 0)
709 stringDrawingState_ = state->next_;
710 if (state->info_ == nil)
711 return MSOldCall(point, font);
713 NSString *info([Info_ objectForKey:state->info_]);
715 return MSOldCall(point, font);
717 NSString *base(state->base_ ?: @"");
718 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]];
722 MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) {
723 WBStringDrawingState *state(stringDrawingState_);
725 return MSOldCall(font);
727 if (--state->count_ == 0)
728 stringDrawingState_ = state->next_;
729 if (state->info_ == nil)
730 return MSOldCall(font);
732 NSString *info([Info_ objectForKey:state->info_]);
734 return MSOldCall(font);
736 NSString *base(state->base_ ?: @"");
737 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info] forWidth:65535];
740 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
741 WBStringDrawingState badgeState = {NULL, 1, @""
745 stringDrawingState_ = &badgeState;
747 UIImage *image(MSOldCall(text));
749 stringDrawingState_ = NULL;
753 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
754 WBStringDrawingState dayState = {NULL, 2, @""
756 // XXX: this is only correct on an iPod dock
757 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
758 , @"CalendarIconDayStyle"};
760 WBStringDrawingState sizeState = {&dayState, 7, nil, nil};
762 WBStringDrawingState dateState = {&sizeState, 2, @""
764 , @"CalendarIconDateStyle"};
766 stringDrawingState_ = &dateState;
768 UIImage *image(MSOldCall(type));
770 stringDrawingState_ = NULL;
774 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
775 NSBundle *bundle([NSBundle mainBundle]);
777 CFLocaleRef locale(CFLocaleCopyCurrent());
778 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
781 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
783 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
784 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
785 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
786 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
790 CFRelease(formatter);
792 NSString *datestyle([@""
793 "font-family: Helvetica; "
794 "font-weight: bold; "
797 "" stringByAppendingString:(IsWild_
798 ? @"font-size: 54px; "
799 : @"font-size: 39px; "
802 NSString *daystyle([@""
803 "font-family: Helvetica; "
804 "font-weight: bold; "
806 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
807 "" stringByAppendingString:(IsWild_
808 ? @"font-size: 11px; "
809 : @"font-size: 9px; "
812 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
813 datestyle = [datestyle stringByAppendingString:style];
814 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
815 daystyle = [daystyle stringByAppendingString:style];
817 float width([self bounds].size.width);
819 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
820 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
822 unsigned base0(IsWild_ ? 89 : 70);
823 if ($GSFontGetUseLegacyFontMetrics())
825 unsigned base1(IsWild_ ? 18 : 16);
832 [(NSString *)date drawAtPoint:CGPointMake(
833 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
834 ) withStyle:datestyle];
836 [(NSString *)day drawAtPoint:CGPointMake(
837 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
838 ) withStyle:daystyle];
844 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
845 void $setBarStyle$_(NSString *name, int &style) {
847 NSLog(@"WB:Debug:%@Style:%d", name, style);
848 NSNumber *number = nil;
850 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
852 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
854 style = [number intValue];
856 NSLog(@"WB:Debug:%@Style=%d", name, style);
860 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
861 $setBarStyle$_(@"Toolbar", style);
862 return MSOldCall(style);
865 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
866 $setBarStyle$_(@"NavigationBar", style);
867 return MSOldCall(style);
871 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
872 [[self superview] setBackgroundColor:[UIColor clearColor]];
873 _SBButtonBar$didMoveToSuperview(self, sel);
876 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
877 [[self superview] setBackgroundColor:[UIColor clearColor]];
878 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
881 static NSArray *Wallpapers_;
882 static bool Papered_;
884 static bool SMSBackgrounded_;
885 static NSString *WallpaperFile_;
886 static UIImageView *WallpaperImage_;
887 static UIWebDocumentView *WallpaperPage_;
888 static NSURL *WallpaperURL_;
890 #define _release(object) \
891 do if (object != nil) { \
896 static UIImage *$getImage$(NSString *path) {
897 UIImage *image([UIImage imageWithContentsOfFile:path]);
899 unsigned scale($getScale$(path));
900 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
901 [image setScale:scale];
906 static UIImage *$getDefaultDesktopImage$() {
907 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
908 return $getImage$(path);
912 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
913 return $getDefaultDesktopImage$() ?: MSOldCall();
916 MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
917 return $getDefaultDesktopImage$() ?: MSOldCall();
920 MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
921 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
922 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
923 if (UIImage *image = $getDefaultDesktopImage$()) {
924 [self setImage:image];
934 // %hook -[SBUIController init] {{{
935 MSInstanceMessageHook0(id, SBUIController, init) {
940 NSString *paper($getTheme$(Wallpapers_));
942 paper = [paper stringByDeletingLastPathComponent];
946 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
947 char *machine = new char[size];
949 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
950 perror("sysctlbyname(\"hw.machine\", ?)");
955 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
959 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
962 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
963 if (&_wallpaperView != NULL) {
964 [_wallpaperView removeFromSuperview];
965 [_wallpaperView release];
966 _wallpaperView = nil;
970 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
971 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
974 if (&_contentLayer != NULL)
975 player = &_contentLayer;
976 else if (&_contentView != NULL)
977 player = &_contentView;
980 UIView *layer(player == NULL ? nil : *player);
982 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
983 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
984 [window setContentView:content];
986 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
987 [window setBackgroundColor:[_window backgroundColor]];
988 [_window setBackgroundColor:[UIColor clearColor]];
990 [window setLevel:-1000];
991 [window setHidden:NO];
993 /*if (player != NULL)
996 [content setBackgroundColor:[layer backgroundColor]];
997 [layer setBackgroundColor:[UIColor clearColor]];
1000 if (!SummerBoard_ || !IsWild_)
1003 CGRect bounds([content bounds]);
1004 bounds.origin.y = -30;
1005 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
1006 [content addSubview:indirect];
1007 [indirect zoomToScale:2.4];
1010 _release(WallpaperFile_);
1011 _release(WallpaperImage_);
1012 _release(WallpaperPage_);
1013 _release(WallpaperURL_);
1016 NSArray *themes([NSArray arrayWithObject:paper]);
1018 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1022 static AVController *controller_(nil);
1023 if (controller_ == nil) {
1024 AVQueue *queue([AVQueue avQueue]);
1025 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1028 AVQueue *queue([controller_ queue]);
1030 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1031 [controller_ setLayer:[video _layer]];
1033 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1034 [queue appendItem:item error:&error];
1036 [controller_ play:&error];
1037 #elif UseMPMoviePlayerController
1038 NSURL *url([NSURL fileURLWithPath:path]);
1039 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1040 controller.movieControlMode = MPMovieControlModeHidden;
1043 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1044 [video setMovieWithPath:path];
1045 [video setRepeatMode:1];
1046 [video setRepeatGap:-1];
1047 [video playFromBeginning];;
1050 [indirect addSubview:video];
1053 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1054 if (UIImage *image = $getImage$(path)) {
1055 WallpaperFile_ = [path retain];
1056 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1057 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1058 [WallpaperImage_ setAlpha:[number floatValue]];
1059 [indirect addSubview:WallpaperImage_];
1063 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1064 CGRect bounds = [indirect bounds];
1066 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1067 [view setAutoresizes:true];
1069 WallpaperPage_ = [view retain];
1070 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1072 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1074 [view setBackgroundColor:[UIColor clearColor]];
1075 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1076 [view setDrawsBackground:NO];
1077 [[view webView] setDrawsBackground:NO];
1079 [indirect addSubview:view];
1083 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1084 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1085 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1086 if ([Manager_ fileExistsAtPath:html]) {
1087 CGRect bounds = [indirect bounds];
1089 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1090 [view setAutoresizes:true];
1092 NSURL *url = [NSURL fileURLWithPath:html];
1093 [view loadRequest:[NSURLRequest requestWithURL:url]];
1095 [view setBackgroundColor:[UIColor clearColor]];
1096 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1097 [view setDrawsBackground:NO];
1098 [[view webView] setDrawsBackground:NO];
1100 [indirect addSubview:view];
1108 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1109 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1110 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1112 if (path != nil && _backgroundView != nil)
1115 _SBAwayView$updateDesktopImage$(self, sel, image);
1118 CGRect bounds = [self bounds];
1120 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1121 [view setAutoresizes:true];
1123 if (WallpaperPage_ != nil)
1124 [WallpaperPage_ release];
1125 WallpaperPage_ = [view retain];
1127 if (WallpaperURL_ != nil)
1128 [WallpaperURL_ release];
1129 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1131 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1133 [[view webView] setDrawsBackground:false];
1134 [view setBackgroundColor:[UIColor clearColor]];
1136 [self insertSubview:view aboveSubview:_backgroundView];
1140 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1141 extern "C" CGColorRef CGGStateGetFillColor(void *);
1142 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1143 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1145 /* WBTimeLabel {{{ */
1146 @interface WBTimeLabel : NSProxy {
1148 _transient SBStatusBarTimeView *view_;
1151 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1155 @implementation WBTimeLabel
1162 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1163 time_ = [time retain];
1168 - (NSString *) description {
1174 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1175 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1176 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1178 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1179 "font-family: Helvetica; "
1180 "font-weight: bold; "
1183 "%@", _mode ? @"white" : @"black", custom]];
1188 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1193 /* WBBadgeLabel {{{ */
1194 @interface WBBadgeLabel : NSProxy {
1198 - (id) initWithBadge:(NSString *)badge;
1199 - (NSString *) description;
1203 @implementation WBBadgeLabel
1210 - (id) initWithBadge:(NSString *)badge {
1211 badge_ = [badge retain];
1215 - (NSString *) description {
1216 return [badge_ description];
1221 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1222 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1223 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1224 "font-family: Helvetica; "
1225 "font-weight: bold; "
1233 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1240 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1241 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1242 alpha = [number floatValue];
1243 return MSOldCall(alpha);
1246 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1247 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1248 alpha = [number floatValue];
1249 return MSOldCall(alpha);
1252 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1253 if ((self = MSOldCall()) != nil) {
1254 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1255 // XXX: note: this is overridden above, which is silly
1256 float alpha([number floatValue]);
1257 [self setIconImageAlpha:alpha];
1258 [self setIconLabelAlpha:alpha];
1263 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1264 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1265 alpha = [number floatValue];
1266 return MSOldCall(alpha);
1270 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1271 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1272 id &_badge(MSHookIvar<id>(self, "_badge"));
1274 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1279 void SBStatusBarController$setStatusBarMode(int &mode) {
1281 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1282 if (mode < 100) // 104:hidden 105:glowing
1283 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1284 mode = [number intValue];
1287 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1288 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1289 SBStatusBarController$setStatusBarMode(mode);
1290 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1293 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1294 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1295 SBStatusBarController$setStatusBarMode(mode);
1296 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1299 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) {
1300 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1301 SBStatusBarController$setStatusBarMode(mode);
1302 //NSLog(@"mode=%u", mode);
1303 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1306 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1307 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1308 mode = [number intValue];
1309 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1312 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1313 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1315 NSLog(@"operatorNameStyle= %@", style);
1316 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1317 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1321 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1323 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1324 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1327 // XXX: replace this with [SBStatusBarTimeView tile]
1328 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1329 id &_time(MSHookIvar<id>(self, "_time"));
1330 if (_time != nil && [_time class] != [WBTimeLabel class])
1331 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1332 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1335 @interface UIView (WinterBoard)
1336 - (bool) wb$isWBImageView;
1337 - (void) wb$logHierarchy;
1338 - (void) wb$setBackgroundColor:(UIColor *)color;
1341 @implementation UIView (WinterBoard)
1343 - (bool) wb$isWBImageView {
1347 - (void) wb$logHierarchy {
1348 WBLogHierarchy(self);
1351 - (void) wb$setBackgroundColor:(UIColor *)color {
1352 [self setBackgroundColor:color];
1353 for (UIView *child in [self subviews])
1354 [child wb$setBackgroundColor:color];
1359 @interface WBImageView : UIImageView {
1362 - (bool) wb$isWBImageView;
1363 - (void) wb$updateFrame;
1366 @implementation WBImageView
1368 - (bool) wb$isWBImageView {
1372 - (void) wb$updateFrame {
1373 CGRect frame([self frame]);
1376 for (UIView *view(self); ; ) {
1377 view = [view superview];
1380 frame.origin.y -= [view frame].origin.y;
1383 [self setFrame:frame];
1388 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1389 NSArray *subviews([self subviews]);
1390 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1391 if (view != nil && [view wb$isWBImageView])
1392 [view wb$updateFrame];
1393 _SBIconList$setFrame$(self, sel, frame);
1396 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1397 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1398 NSArray *lists([_iconModel iconLists]);
1400 for (unsigned i(0), e([lists count]); i != e; ++i)
1401 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]])) {
1402 SBIconList *list([lists objectAtIndex:i]);
1403 NSArray *subviews([list subviews]);
1405 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1406 if (view == nil || ![view wb$isWBImageView]) {
1407 view = [[[WBImageView alloc] init] autorelease];
1408 [list insertSubview:view atIndex:0];
1411 UIImage *image([UIImage imageWithContentsOfFile:path]);
1413 CGRect frame([view frame]);
1414 frame.size = [image size];
1415 [view setFrame:frame];
1417 [view setImage:image];
1418 [view wb$updateFrame];
1421 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1424 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1425 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1427 [self setClipsToBounds:NO];
1431 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1432 static bool gssc(false);
1434 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1435 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1438 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1439 [Info_ setObject:[NSNumber numberWithBool:(
1441 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1442 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1443 )] forKey:@"UndockedIconLabels"];
1446 id &_label(MSHookIvar<id>(self, "_label"));
1447 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1450 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1451 [_label setInDock:docked];
1453 _SBIconLabel$setInDock$(self, sel, docked);
1454 [self setNeedsDisplay];
1457 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1458 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1461 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1462 _SBDockIconListView$setFrame$(self, sel, frame);
1465 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1466 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1467 NSString *identifier = [self bundleIdentifier];
1468 NSLocale *locale = [NSLocale currentLocale];
1469 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1471 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1472 NSString *file = table == nil ? @"Localizable" : table;
1473 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1474 NSDictionary *strings;
1475 if ((strings = [Strings_ objectForKey:name]) != nil) {
1476 if (static_cast<id>(strings) != [NSNull null]) strings:
1477 if (NSString *value = [strings objectForKey:key])
1479 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1482 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1483 [Strings_ setObject:[strings autorelease] forKey:name];
1487 [Strings_ setObject:[NSNull null] forKey:name];
1488 return MSOldCall(key, value, table);
1491 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1492 MSClassHook(WebCoreFrameBridge)
1494 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1497 void **core(reinterpret_cast<void **>([node _node]));
1498 if (core == NULL || core[6] == NULL)
1500 return MSOldCall(node, width);
1504 MSInstanceMessageHook1(void, SBIconLabel, drawRect, CGRect, rect) {
1505 CGRect bounds = [self bounds];
1507 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1510 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1511 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1513 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1515 NSString *style = [NSString stringWithFormat:@""
1516 "font-family: Helvetica; "
1517 "font-weight: bold; "
1519 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1520 ? @"font-size: 12px; "
1521 : @"font-size: 11px; "
1525 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1527 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1529 bool ellipsis(false);
1530 float max = [self frame].size.width - 11, width;
1532 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
1535 size_t length([label length]);
1536 float spacing((width - max) / (length - 1));
1538 if (spacing > 1.25) {
1540 label = [label substringToIndex:(length - 1)];
1544 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
1548 label = [label stringByAppendingString:@"..."];
1550 if (NSString *custom = [Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")])
1551 style = [style stringByAppendingString:custom];
1553 CGSize size = [label sizeWithStyle:style forWidth:bounds.size.width];
1554 [label drawAtPoint:CGPointMake((bounds.size.width - size.width) / 2, 0) withStyle:style];
1558 MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1559 if ((self = MSOldCall(frame, delegate)) != nil) {
1560 [self setBackgroundColor:[UIColor clearColor]];
1564 MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1565 return SMSBackgrounded_ ? NO : MSOldCall();
1568 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1569 [self wb$setBackgroundColor:[UIColor clearColor]];
1573 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1575 [balloon setBackgroundColor:[UIColor clearColor]];
1578 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1579 MSOldCall([UIColor clearColor]);
1580 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1584 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1585 if ((self = MSOldCall(style, reuse)) != nil) {
1586 [self setBackgroundColor:[UIColor clearColor]];
1587 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1592 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1593 if ((self = MSOldCall(style, reuse)) != nil) {
1594 [self setBackgroundColor:[UIColor clearColor]];
1595 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1599 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1600 if ((self = MSOldCall(style, reuse)) != nil) {
1601 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1602 [_label setBackgroundColor:[UIColor clearColor]];
1606 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1607 MSOldCall(UITableViewCellSeparatorStyleNone);
1610 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1611 if ((self = MSOldCall(frame, style)) != nil) {
1612 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1616 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1619 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1620 if (UIImage *image = $getImage$(path)) {
1621 SMSBackgrounded_ = true;
1623 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1624 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1626 if (&_transcriptTable != NULL)
1627 table = _transcriptTable;
1628 else if (&_transcriptLayer != NULL)
1629 table = _transcriptLayer;
1633 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1634 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1637 [placard insertSubview:background atIndex:0];
1639 [table setBackgroundColor:[UIColor clearColor]];
1640 [placard insertSubview:background belowSubview:table];
1646 // %hook _UIImageWithName() {{{
1647 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1649 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1656 if (_UIPackedImageTableGetIdentifierForName != NULL)
1657 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1658 else if (_UISharedImageNameGetIdentifier != NULL) {
1659 identifier = _UISharedImageNameGetIdentifier(name);
1660 packed = identifier != -1;
1667 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1670 return __UIImageWithName(name);
1672 NSNumber *key([NSNumber numberWithInt:identifier]);
1673 UIImage *image([UIImages_ objectForKey:key]);
1675 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1676 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1677 image = $getImage$(path);
1678 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1682 image = __UIImageWithName(name);
1685 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1686 if (![Manager_ fileExistsAtPath:path])
1687 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1694 // %hook _UIImageWithNameInDomain() {{{
1695 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1696 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1697 UIImage *image([PathImages_ objectForKey:key]);
1699 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1701 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1702 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1703 image = $getImage$(path);
1704 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1705 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1709 // %hook GSFontCreateWithName() {{{
1710 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1712 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1713 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1714 name = [font UTF8String];
1715 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1716 // size *= [scale floatValue];
1717 return _GSFontCreateWithName(name, traits, size);
1721 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1722 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1724 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1726 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1728 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1729 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1731 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1734 NSString *path = [NSString stringWithUTF8String:a1];
1735 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1736 NSString *file = [path substringFromIndex:31];
1737 for (NSString *theme in Themes_) {
1738 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1739 if ([Manager_ fileExistsAtPath:path]) {
1740 strcpy(a1, [path UTF8String]);
1749 static void ChangeWallpaper(
1750 CFNotificationCenterRef center,
1754 CFDictionaryRef info
1757 NSLog(@"WB:Debug:ChangeWallpaper!");
1760 if (WallpaperFile_ != nil) {
1761 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1763 image = [image autorelease];
1766 if (WallpaperImage_ != nil)
1767 [WallpaperImage_ setImage:image];
1768 if (WallpaperPage_ != nil)
1769 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1773 #define WBRename(name, sel, imp) \
1774 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
1776 template <typename Type_>
1777 static void msset(Type_ &function, MSImageRef image, const char *name) {
1778 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1781 template <typename Type_>
1782 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1783 struct nlist &name(nl[index]);
1784 uintptr_t value(name.n_value);
1785 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1786 value |= 0x00000001;
1787 function = reinterpret_cast<Type_>(value);
1790 template <typename Type_>
1791 static void dlset(Type_ &function, const char *name) {
1792 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1795 // %hook CGImageReadCreateWithFile() {{{
1796 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1798 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1799 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1800 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1806 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
1807 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1808 if (style == nil || [style length] == 0)
1809 style = @"font-family: Helvetica; font-size: 12px";
1810 return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
1813 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
1814 if (style == nil || [style length] == 0)
1815 style = @"font-family: Helvetica; font-size: 12px";
1816 return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width];
1819 static void SBInitialize() {
1820 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
1821 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
1824 WBRename(SBApplication, pathForIcon, pathForIcon);
1825 WBRename(SBApplicationIcon, icon, icon);
1826 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1829 WBRename(SBBookmarkIcon, icon, icon);
1830 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1831 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1832 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1833 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
1835 WBRename(SBWidgetApplicationIcon, icon, icon);
1837 WBRename(SBDockIconListView, setFrame:, setFrame$);
1838 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
1840 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
1841 WBRename(SBIconLabel, setInDock:, setInDock$);
1843 WBRename(SBIconList, setFrame:, setFrame$);
1845 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
1846 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
1847 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
1848 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
1850 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
1851 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
1852 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
1854 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
1856 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
1857 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
1858 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
1859 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
1860 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
1861 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
1862 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
1863 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
1864 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
1867 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
1871 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1873 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
1874 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
1876 Manager_ = [[NSFileManager defaultManager] retain];
1877 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
1879 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
1881 // Load Settings.plist {{{
1882 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
1883 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
1884 SummerBoard_ = [value boolValue];
1885 if (NSNumber *value = [settings objectForKey:@"Debug"])
1886 Debug_ = [value boolValue];
1887 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
1888 UIDebug_ = [value boolValue];
1890 NSArray *themes([settings objectForKey:@"Themes"]);
1892 if (NSString *theme = [settings objectForKey:@"Theme"])
1893 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
1895 [NSNumber numberWithBool:true], @"Active",
1899 for (NSDictionary *theme in themes) {
1900 NSNumber *active([theme objectForKey:@"Active"]);
1901 if (![active boolValue])
1904 NSString *name([theme objectForKey:@"Name"]);
1908 NSString *theme(nil);
1910 #define testForTheme(format...) \
1911 if (theme == nil) { \
1912 NSString *path = [NSString stringWithFormat:format]; \
1913 if ([Manager_ fileExistsAtPath:path]) { \
1914 [Themes_ addObject:path]; \
1919 testForTheme(@"/Library/Themes/%@.theme", name)
1920 testForTheme(@"/Library/Themes/%@", name)
1921 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
1926 // Merge Info.plist {{{
1927 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1929 for (NSString *theme in Themes_)
1930 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
1931 for (NSString *key in [info allKeys])
1932 if ([Info_ objectForKey:key] == nil)
1933 [Info_ setObject:[info objectForKey:key] forKey:key];
1937 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
1938 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
1939 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
1942 // GraphicsServices {{{
1944 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
1948 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
1949 void *(*CGImageReadCreateWithFile)(NSString *, int);
1950 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
1951 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
1956 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
1957 Papered_ = $getTheme$(Wallpapers_) != nil;
1958 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
1960 CFNotificationCenterAddObserver(
1961 CFNotificationCenterGetDarwinNotifyCenter(),
1962 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
1965 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
1966 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
1967 if (MediaPlayer != nil)
1970 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
1971 $MPVideoView = objc_getClass("MPVideoView");
1978 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
1980 memset(nl, 0, sizeof(nl));
1981 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
1982 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
1983 nl[2].n_un.n_name = (char *) "__UIKitBundle";
1984 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
1985 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
1988 nlset(_UIApplicationImageWithName, nl, 0);
1989 nlset(_UIImageWithNameInDomain, nl, 1);
1990 nlset(_UIKitBundle, nl, 2);
1991 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
1992 nlset(_UISharedImageNameGetIdentifier, nl, 4);
1994 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
1995 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
1996 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
2000 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
2001 NSError *error(nil);
2002 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
2003 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
2005 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);