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) {
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 NSString *rest([base substringWithRange:NSMakeRange(0, [base length] - 3)]);
280 [scaled addObject:[NSString stringWithFormat:@"%@~iphone.%@", rest, extension]];
281 [scaled addObject:[rest stringByAppendingPathExtension:extension]];
283 // XXX: this code isn't really complete
285 [scaled addObject:file];
287 if ([base hasSuffix:@"~iphone"])
288 [scaled addObject:[[base substringWithRange:NSMakeRange(0, [base length] - 7)] stringByAppendingPathExtension:extension]];
295 static NSString *$getTheme$(NSArray *files, NSArray *themes = Themes_) {
296 if (NSString *path = [Themed_ objectForKey:files])
297 return reinterpret_cast<id>(path) == [NSNull null] ? nil : path;
300 NSLog(@"WB:Debug: %@", [files description]);
304 for (NSString *theme in Themes_)
305 for (NSString *file in files) {
306 path = [NSString stringWithFormat:@"%@/%@", theme, file];
307 if ([Manager_ fileExistsAtPath:path])
314 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:files];
318 // $pathForFile$inBundle$() {{{
319 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool ui) {
320 NSString *identifier = [bundle bundleIdentifier];
321 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
323 if (identifier != nil)
324 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
325 if (NSString *folder = [[bundle bundlePath] lastPathComponent])
326 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
328 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
330 #define remapResourceName(oldname, newname) \
331 else if ([file isEqualToString:(oldname)]) \
332 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
334 bool summer(SpringBoard_ && SummerBoard_);
336 if (identifier == nil);
337 else if ([identifier isEqualToString:@"com.apple.chatkit"])
338 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
339 else if ([identifier isEqualToString:@"com.apple.calculator"])
340 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
342 remapResourceName(@"FSO_BG.png", @"StatusBar")
343 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
344 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
346 if (NSString *path = $getTheme$($useScale$(names, ui)))
353 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
354 NSString *identifier = [self bundleIdentifier];
355 NSString *path = [self path];
356 NSString *folder = [path lastPathComponent];
357 NSString *dname = [self displayName];
358 NSString *didentifier = [self displayIdentifier];
361 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
363 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
365 /* XXX: I might need to keep this for backwards compatibility
366 if (identifier != nil)
367 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
369 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
371 #define testForIcon(Name) \
372 if (NSString *name = Name) \
373 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
375 if (![didentifier isEqualToString:identifier])
376 testForIcon(didentifier);
378 testForIcon(identifier);
381 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
384 if (didentifier != nil) {
385 testForIcon([English_ objectForKey:didentifier]);
387 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
388 if ([parts count] != 1)
389 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
390 testForIcon([english objectForKey:[parts lastObject]]);
393 if (NSString *path = $getTheme$(names))
399 // -[NSBundle wb$bundleWithFile] {{{
400 @interface NSBundle (WinterBoard)
401 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
404 @implementation NSBundle (WinterBoard)
406 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
407 path = [path stringByDeletingLastPathComponent];
408 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
411 NSBundle *bundle([Bundles_ objectForKey:path]);
412 if (reinterpret_cast<id>(bundle) == [NSNull null])
414 else if (bundle == nil) {
415 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
416 bundle = [NSBundle bundleWithPath:path];
418 bundle = [NSBundle wb$bundleWithFile:path];
420 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
421 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
429 // -[NSString wb$themedPath] {{{
430 @interface NSString (WinterBoard)
431 - (NSString *) wb$themedPath;
434 @implementation NSString (WinterBoard)
436 - (NSString *) wb$themedPath {
437 if ([self hasPrefix:@"/Library/Themes/"])
441 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
443 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
444 NSString *file([self stringByResolvingSymlinksInPath]);
445 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
446 if ([file hasPrefix:prefix]) {
447 NSUInteger length([prefix length]);
448 if (length != [file length])
449 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
460 void WBLogRect(const char *tag, struct CGRect rect) {
461 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
464 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
465 CGRect frame([view frame]);
466 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]);
468 for (UIView *child in [view subviews])
469 WBLogHierarchy(child, index++, indent + 1);
472 UIImage *$cacheForImage$(UIImage *image) {
473 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
474 CGRect rect = {CGPointMake(1, 1), [image size]};
475 CGSize size = {rect.size.width + 2, rect.size.height + 2};
477 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
478 CGColorSpaceRelease(space);
480 CGContextDrawImage(context, rect, [image CGImage]);
481 CGImageRef ref(CGBitmapContextCreateImage(context));
482 CGContextRelease(context);
484 UIImage *cache([UIImage imageWithCGImage:ref]);
490 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
491 //if ([name isEqualToString:@"icons"]) return nil;
492 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
495 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
496 NSString *key([icon displayIdentifier]);
498 if (UIImage *image = [icon icon]) {
499 CGSize size = [image size];
500 if (size.width != 59 || size.height != 60) {
501 UIImage *cache($cacheForImage$(image));
502 [Cache_ setObject:cache forKey:key];
507 _SBIconModel$cacheImageForIcon$(self, sel, icon);
510 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
511 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
512 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
514 NSString *key([icon displayIdentifier]);
516 if (UIImage *image = [icon icon]) {
517 CGSize size = [image size];
518 if (size.width != 59 || size.height != 60) {
519 UIImage *cache($cacheForImage$(image));
520 [Cache_ setObject:cache forKey:key];
526 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
527 NSString *key([icon displayIdentifier]);
528 if (UIImage *image = [Cache_ objectForKey:key])
531 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
534 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
536 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
537 NSString *key([icon displayIdentifier]);
538 if (UIImage *image = [Cache_ objectForKey:key])
541 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
544 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
545 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
546 [self setBackgroundColor:[UIColor clearColor]];
547 for (UIView *child in [self subviews])
548 [child setBackgroundColor:[UIColor clearColor]];
552 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
553 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
554 [self setBackgroundColor:[UIColor clearColor]];
558 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
559 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
560 float inset([self edgeInset]);
561 [[UIColor clearColor] set];
562 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
563 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
566 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
567 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
568 if (NSString *path = $pathForIcon$([self application]))
569 return [UIImage imageWithContentsOfFile:path];
570 return _SBApplicationIcon$icon(self, sel);
573 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
575 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
576 if (IsWild_ && false) // XXX: delete this code, it should not be supported
577 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
578 return [UIImage imageWithContentsOfFile:path72];
579 if (NSString *path = $pathForIcon$([self application]))
580 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
582 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
583 width = [$SBIcon defaultIconImageSize].width;
586 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
589 return _SBApplicationIcon$generateIconImage$(self, sel, type);
592 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
594 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
595 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
596 return [UIImage imageWithContentsOfFile:path];
597 return _SBWidgetApplicationIcon$icon(self, sel);
600 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
602 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
603 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
604 return [UIImage imageWithContentsOfFile:path];
605 return _SBBookmarkIcon$icon(self, sel);
608 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
609 if (NSString *path = $pathForIcon$(self))
611 return _SBApplication$pathForIcon(self, sel);
614 static UIImage *CachedImageAtPath(NSString *path) {
615 path = [path stringByResolvingSymlinksInPath];
616 UIImage *image = [PathImages_ objectForKey:path];
618 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
619 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
621 image = [image autorelease];
622 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
626 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
627 NSBundle *bundle = [NSBundle mainBundle];
629 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
630 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
631 return CachedImageAtPath(path);
632 return __UIApplicationImageWithName(name);
635 #define WBDelegate(delegate) \
636 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
638 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
639 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
641 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
645 - (void) forwardInvocation:(NSInvocation*)inv { \
646 SEL sel = [inv selector]; \
647 if ([delegate respondsToSelector:sel]) \
648 [inv invokeWithTarget:delegate]; \
650 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
653 // %hook -[NSBundle pathForResource:ofType:] {{{
654 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
655 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
657 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
658 if (NSString *path = $pathForFile$inBundle$(file, self, false))
660 return MSOldCall(resource, type);
664 static struct WBStringDrawingState {
665 WBStringDrawingState *next_;
669 } *stringDrawingState_;
671 MSInstanceMessageHook4(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode, CGPoint, point, float, width, UIFont *, font, int, mode) {
672 WBStringDrawingState *state(stringDrawingState_);
674 return MSOldCall(point, width, font, mode);
676 if (--state->count_ == 0)
677 stringDrawingState_ = state->next_;
678 if (state->info_ == nil)
679 return MSOldCall(point, width, font, mode);
681 NSString *info([Info_ objectForKey:state->info_]);
683 return MSOldCall(point, width, font, mode);
685 NSString *base(state->base_ ?: @"");
686 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]];
690 MSInstanceMessageHook2(CGSize, NSString, drawAtPoint,withFont, CGPoint, point, UIFont *, font) {
691 WBStringDrawingState *state(stringDrawingState_);
693 return MSOldCall(point, font);
695 if (--state->count_ == 0)
696 stringDrawingState_ = state->next_;
697 if (state->info_ == nil)
698 return MSOldCall(point, font);
700 NSString *info([Info_ objectForKey:state->info_]);
702 return MSOldCall(point, font);
704 NSString *base(state->base_ ?: @"");
705 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]];
709 MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) {
710 WBStringDrawingState *state(stringDrawingState_);
712 return MSOldCall(font);
714 if (--state->count_ == 0)
715 stringDrawingState_ = state->next_;
716 if (state->info_ == nil)
717 return MSOldCall(font);
719 NSString *info([Info_ objectForKey:state->info_]);
721 return MSOldCall(font);
723 NSString *base(state->base_ ?: @"");
724 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info] forWidth:65535];
727 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
728 WBStringDrawingState badgeState = {NULL, 1, @""
732 stringDrawingState_ = &badgeState;
734 UIImage *image(MSOldCall(text));
736 stringDrawingState_ = NULL;
740 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
741 WBStringDrawingState dayState = {NULL, 2, @""
743 // XXX: this is only correct on an iPod dock
744 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
745 , @"CalendarIconDayStyle"};
747 WBStringDrawingState sizeState = {&dayState, 7, nil, nil};
749 WBStringDrawingState dateState = {&sizeState, 2, @""
751 , @"CalendarIconDateStyle"};
753 stringDrawingState_ = &dateState;
755 UIImage *image(MSOldCall(type));
757 stringDrawingState_ = NULL;
761 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
762 NSBundle *bundle([NSBundle mainBundle]);
764 CFLocaleRef locale(CFLocaleCopyCurrent());
765 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
768 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
770 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
771 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
772 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
773 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
777 CFRelease(formatter);
779 NSString *datestyle([@""
780 "font-family: Helvetica; "
781 "font-weight: bold; "
784 "" stringByAppendingString:(IsWild_
785 ? @"font-size: 54px; "
786 : @"font-size: 39px; "
789 NSString *daystyle([@""
790 "font-family: Helvetica; "
791 "font-weight: bold; "
793 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
794 "" stringByAppendingString:(IsWild_
795 ? @"font-size: 11px; "
796 : @"font-size: 9px; "
799 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
800 datestyle = [datestyle stringByAppendingString:style];
801 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
802 daystyle = [daystyle stringByAppendingString:style];
804 float width([self bounds].size.width);
806 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
807 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
809 unsigned base0(IsWild_ ? 89 : 70);
810 if ($GSFontGetUseLegacyFontMetrics())
812 unsigned base1(IsWild_ ? 18 : 16);
819 [(NSString *)date drawAtPoint:CGPointMake(
820 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
821 ) withStyle:datestyle];
823 [(NSString *)day drawAtPoint:CGPointMake(
824 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
825 ) withStyle:daystyle];
831 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
832 void $setBarStyle$_(NSString *name, int &style) {
834 NSLog(@"WB:Debug:%@Style:%d", name, style);
835 NSNumber *number = nil;
837 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
839 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
841 style = [number intValue];
843 NSLog(@"WB:Debug:%@Style=%d", name, style);
847 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
848 $setBarStyle$_(@"Toolbar", style);
849 return MSOldCall(style);
852 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
853 $setBarStyle$_(@"NavigationBar", style);
854 return MSOldCall(style);
858 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
859 [[self superview] setBackgroundColor:[UIColor clearColor]];
860 _SBButtonBar$didMoveToSuperview(self, sel);
863 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
864 [[self superview] setBackgroundColor:[UIColor clearColor]];
865 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
868 static NSArray *Wallpapers_;
869 static bool Papered_;
871 static bool SMSBackgrounded_;
872 static NSString *WallpaperFile_;
873 static UIImageView *WallpaperImage_;
874 static UIWebDocumentView *WallpaperPage_;
875 static NSURL *WallpaperURL_;
877 #define _release(object) \
878 do if (object != nil) { \
883 static UIImage *$getImage$(NSString *path) {
884 UIImage *image([UIImage imageWithContentsOfFile:path]);
886 unsigned scale($getScale$(path));
887 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
888 [image setScale:scale];
893 static UIImage *$getDefaultDesktopImage$() {
894 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
895 return $getImage$(path);
899 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
900 return $getDefaultDesktopImage$() ?: MSOldCall();
903 MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
904 return $getDefaultDesktopImage$() ?: MSOldCall();
907 MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
908 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
909 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
910 if (UIImage *image = $getDefaultDesktopImage$()) {
911 [self setImage:image];
921 // %hook -[SBUIController init] {{{
922 MSInstanceMessageHook0(id, SBUIController, init) {
927 NSString *paper($getTheme$(Wallpapers_));
929 paper = [paper stringByDeletingLastPathComponent];
933 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
934 char *machine = new char[size];
936 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
937 perror("sysctlbyname(\"hw.machine\", ?)");
942 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
946 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
949 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
950 if (&_wallpaperView != NULL) {
951 [_wallpaperView removeFromSuperview];
952 [_wallpaperView release];
953 _wallpaperView = nil;
957 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
958 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
961 if (&_contentLayer != NULL)
962 player = &_contentLayer;
963 else if (&_contentView != NULL)
964 player = &_contentView;
967 UIView *layer(player == NULL ? nil : *player);
969 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
970 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
971 [window setContentView:content];
973 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
974 [window setBackgroundColor:[_window backgroundColor]];
975 [_window setBackgroundColor:[UIColor clearColor]];
977 [window setLevel:-1000];
978 [window setHidden:NO];
980 /*if (player != NULL)
983 [content setBackgroundColor:[layer backgroundColor]];
984 [layer setBackgroundColor:[UIColor clearColor]];
987 if (!SummerBoard_ || !IsWild_)
990 CGRect bounds([content bounds]);
991 bounds.origin.y = -30;
992 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
993 [content addSubview:indirect];
994 [indirect zoomToScale:2.4];
997 _release(WallpaperFile_);
998 _release(WallpaperImage_);
999 _release(WallpaperPage_);
1000 _release(WallpaperURL_);
1003 NSArray *themes([NSArray arrayWithObject:paper]);
1005 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1009 static AVController *controller_(nil);
1010 if (controller_ == nil) {
1011 AVQueue *queue([AVQueue avQueue]);
1012 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1015 AVQueue *queue([controller_ queue]);
1017 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1018 [controller_ setLayer:[video _layer]];
1020 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1021 [queue appendItem:item error:&error];
1023 [controller_ play:&error];
1024 #elif UseMPMoviePlayerController
1025 NSURL *url([NSURL fileURLWithPath:path]);
1026 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1027 controller.movieControlMode = MPMovieControlModeHidden;
1030 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1031 [video setMovieWithPath:path];
1032 [video setRepeatMode:1];
1033 [video setRepeatGap:-1];
1034 [video playFromBeginning];;
1037 [indirect addSubview:video];
1040 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1041 if (UIImage *image = $getImage$(path)) {
1042 WallpaperFile_ = [path retain];
1043 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1044 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1045 [WallpaperImage_ setAlpha:[number floatValue]];
1046 [indirect addSubview:WallpaperImage_];
1050 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1051 CGRect bounds = [indirect bounds];
1053 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1054 [view setAutoresizes:true];
1056 WallpaperPage_ = [view retain];
1057 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1059 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1061 [view setBackgroundColor:[UIColor clearColor]];
1062 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1063 [view setDrawsBackground:NO];
1064 [[view webView] setDrawsBackground:NO];
1066 [indirect addSubview:view];
1070 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1071 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1072 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1073 if ([Manager_ fileExistsAtPath:html]) {
1074 CGRect bounds = [indirect bounds];
1076 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1077 [view setAutoresizes:true];
1079 NSURL *url = [NSURL fileURLWithPath:html];
1080 [view loadRequest:[NSURLRequest requestWithURL:url]];
1082 [view setBackgroundColor:[UIColor clearColor]];
1083 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1084 [view setDrawsBackground:NO];
1085 [[view webView] setDrawsBackground:NO];
1087 [indirect addSubview:view];
1095 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1096 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1097 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1099 if (path != nil && _backgroundView != nil)
1102 _SBAwayView$updateDesktopImage$(self, sel, image);
1105 CGRect bounds = [self bounds];
1107 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1108 [view setAutoresizes:true];
1110 if (WallpaperPage_ != nil)
1111 [WallpaperPage_ release];
1112 WallpaperPage_ = [view retain];
1114 if (WallpaperURL_ != nil)
1115 [WallpaperURL_ release];
1116 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1118 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1120 [[view webView] setDrawsBackground:false];
1121 [view setBackgroundColor:[UIColor clearColor]];
1123 [self insertSubview:view aboveSubview:_backgroundView];
1127 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1128 extern "C" CGColorRef CGGStateGetFillColor(void *);
1129 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1130 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1132 /* WBTimeLabel {{{ */
1133 @interface WBTimeLabel : NSProxy {
1135 _transient SBStatusBarTimeView *view_;
1138 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1142 @implementation WBTimeLabel
1149 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1150 time_ = [time retain];
1155 - (NSString *) description {
1161 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1162 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1163 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1165 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1166 "font-family: Helvetica; "
1167 "font-weight: bold; "
1170 "%@", _mode ? @"white" : @"black", custom]];
1175 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1180 /* WBBadgeLabel {{{ */
1181 @interface WBBadgeLabel : NSProxy {
1185 - (id) initWithBadge:(NSString *)badge;
1186 - (NSString *) description;
1190 @implementation WBBadgeLabel
1197 - (id) initWithBadge:(NSString *)badge {
1198 badge_ = [badge retain];
1202 - (NSString *) description {
1203 return [badge_ description];
1208 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1209 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1210 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1211 "font-family: Helvetica; "
1212 "font-weight: bold; "
1220 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1227 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1228 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1229 alpha = [number floatValue];
1230 return MSOldCall(alpha);
1233 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1234 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1235 alpha = [number floatValue];
1236 return MSOldCall(alpha);
1239 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1240 if ((self = MSOldCall()) != nil) {
1241 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1242 // XXX: note: this is overridden above, which is silly
1243 float alpha([number floatValue]);
1244 [self setIconImageAlpha:alpha];
1245 [self setIconLabelAlpha:alpha];
1250 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1251 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1252 alpha = [number floatValue];
1253 return MSOldCall(alpha);
1257 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1258 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1259 id &_badge(MSHookIvar<id>(self, "_badge"));
1261 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1266 void SBStatusBarController$setStatusBarMode(int &mode) {
1268 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1269 if (mode < 100) // 104:hidden 105:glowing
1270 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1271 mode = [number intValue];
1274 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1275 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1276 SBStatusBarController$setStatusBarMode(mode);
1277 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1280 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1281 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1282 SBStatusBarController$setStatusBarMode(mode);
1283 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1286 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) {
1287 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1288 SBStatusBarController$setStatusBarMode(mode);
1289 //NSLog(@"mode=%u", mode);
1290 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1293 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1294 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1295 mode = [number intValue];
1296 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1299 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1300 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1302 NSLog(@"operatorNameStyle= %@", style);
1303 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1304 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1308 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1310 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1311 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1314 // XXX: replace this with [SBStatusBarTimeView tile]
1315 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1316 id &_time(MSHookIvar<id>(self, "_time"));
1317 if (_time != nil && [_time class] != [WBTimeLabel class])
1318 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1319 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1322 @interface UIView (WinterBoard)
1323 - (bool) wb$isWBImageView;
1324 - (void) wb$logHierarchy;
1325 - (void) wb$setBackgroundColor:(UIColor *)color;
1328 @implementation UIView (WinterBoard)
1330 - (bool) wb$isWBImageView {
1334 - (void) wb$logHierarchy {
1335 WBLogHierarchy(self);
1338 - (void) wb$setBackgroundColor:(UIColor *)color {
1339 [self setBackgroundColor:color];
1340 for (UIView *child in [self subviews])
1341 [child wb$setBackgroundColor:color];
1346 @interface WBImageView : UIImageView {
1349 - (bool) wb$isWBImageView;
1350 - (void) wb$updateFrame;
1353 @implementation WBImageView
1355 - (bool) wb$isWBImageView {
1359 - (void) wb$updateFrame {
1360 CGRect frame([self frame]);
1363 for (UIView *view(self); ; ) {
1364 view = [view superview];
1367 frame.origin.y -= [view frame].origin.y;
1370 [self setFrame:frame];
1375 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1376 NSArray *subviews([self subviews]);
1377 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1378 if (view != nil && [view wb$isWBImageView])
1379 [view wb$updateFrame];
1380 _SBIconList$setFrame$(self, sel, frame);
1383 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1384 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1385 NSArray *lists([_iconModel iconLists]);
1387 for (unsigned i(0), e([lists count]); i != e; ++i)
1388 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]])) {
1389 SBIconList *list([lists objectAtIndex:i]);
1390 NSArray *subviews([list subviews]);
1392 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1393 if (view == nil || ![view wb$isWBImageView]) {
1394 view = [[[WBImageView alloc] init] autorelease];
1395 [list insertSubview:view atIndex:0];
1398 UIImage *image([UIImage imageWithContentsOfFile:path]);
1400 CGRect frame([view frame]);
1401 frame.size = [image size];
1402 [view setFrame:frame];
1404 [view setImage:image];
1405 [view wb$updateFrame];
1408 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1411 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1412 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1414 [self setClipsToBounds:NO];
1418 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1419 static bool gssc(false);
1421 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1422 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1425 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1426 [Info_ setObject:[NSNumber numberWithBool:(
1428 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1429 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1430 )] forKey:@"UndockedIconLabels"];
1433 id &_label(MSHookIvar<id>(self, "_label"));
1434 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1437 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1438 [_label setInDock:docked];
1440 _SBIconLabel$setInDock$(self, sel, docked);
1441 [self setNeedsDisplay];
1444 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1445 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1448 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1449 _SBDockIconListView$setFrame$(self, sel, frame);
1452 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1453 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1454 NSString *identifier = [self bundleIdentifier];
1455 NSLocale *locale = [NSLocale currentLocale];
1456 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1458 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1459 NSString *file = table == nil ? @"Localizable" : table;
1460 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1461 NSDictionary *strings;
1462 if ((strings = [Strings_ objectForKey:name]) != nil) {
1463 if (static_cast<id>(strings) != [NSNull null]) strings:
1464 if (NSString *value = [strings objectForKey:key])
1466 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1469 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1470 [Strings_ setObject:[strings autorelease] forKey:name];
1474 [Strings_ setObject:[NSNull null] forKey:name];
1475 return MSOldCall(key, value, table);
1478 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1479 MSClassHook(WebCoreFrameBridge)
1481 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1484 void **core(reinterpret_cast<void **>([node _node]));
1485 if (core == NULL || core[6] == NULL)
1487 return MSOldCall(node, width);
1491 MSInstanceMessageHook1(void, SBIconLabel, drawRect, CGRect, rect) {
1492 CGRect bounds = [self bounds];
1494 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1497 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1498 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1500 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1502 NSString *style = [NSString stringWithFormat:@""
1503 "font-family: Helvetica; "
1504 "font-weight: bold; "
1506 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1507 ? @"font-size: 12px; "
1508 : @"font-size: 11px; "
1512 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1514 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1516 bool ellipsis(false);
1517 float max = [self frame].size.width - 11, width;
1519 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
1522 size_t length([label length]);
1523 float spacing((width - max) / (length - 1));
1525 if (spacing > 1.25) {
1527 label = [label substringToIndex:(length - 1)];
1531 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
1535 label = [label stringByAppendingString:@"..."];
1537 if (NSString *custom = [Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")])
1538 style = [style stringByAppendingString:custom];
1540 CGSize size = [label sizeWithStyle:style forWidth:bounds.size.width];
1541 [label drawAtPoint:CGPointMake((bounds.size.width - size.width) / 2, 0) withStyle:style];
1545 MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1546 if ((self = MSOldCall(frame, delegate)) != nil) {
1547 [self setBackgroundColor:[UIColor clearColor]];
1551 MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1552 return SMSBackgrounded_ ? NO : MSOldCall();
1555 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1556 [self wb$setBackgroundColor:[UIColor clearColor]];
1560 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1562 [balloon setBackgroundColor:[UIColor clearColor]];
1565 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1566 MSOldCall([UIColor clearColor]);
1567 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1571 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1572 if ((self = MSOldCall(style, reuse)) != nil) {
1573 [self setBackgroundColor:[UIColor clearColor]];
1574 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1579 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1580 if ((self = MSOldCall(style, reuse)) != nil) {
1581 [self setBackgroundColor:[UIColor clearColor]];
1582 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1586 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1587 if ((self = MSOldCall(style, reuse)) != nil) {
1588 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1589 [_label setBackgroundColor:[UIColor clearColor]];
1593 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1594 MSOldCall(UITableViewCellSeparatorStyleNone);
1597 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1598 if ((self = MSOldCall(frame, style)) != nil) {
1599 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1603 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1606 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1607 if (UIImage *image = $getImage$(path)) {
1608 SMSBackgrounded_ = true;
1610 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1611 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1613 if (&_transcriptTable != NULL)
1614 table = _transcriptTable;
1615 else if (&_transcriptLayer != NULL)
1616 table = _transcriptLayer;
1620 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1621 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1624 [placard insertSubview:background atIndex:0];
1626 [table setBackgroundColor:[UIColor clearColor]];
1627 [placard insertSubview:background belowSubview:table];
1633 // %hook _UIImageWithName() {{{
1634 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1636 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1643 if (_UIPackedImageTableGetIdentifierForName != NULL)
1644 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1645 else if (_UISharedImageNameGetIdentifier != NULL) {
1646 identifier = _UISharedImageNameGetIdentifier(name);
1647 packed = identifier != -1;
1654 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1657 return __UIImageWithName(name);
1659 NSNumber *key([NSNumber numberWithInt:identifier]);
1660 UIImage *image([UIImages_ objectForKey:key]);
1662 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1663 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1664 image = $getImage$(path);
1665 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1669 image = __UIImageWithName(name);
1672 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1673 if (![Manager_ fileExistsAtPath:path])
1674 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1681 // %hook _UIImageWithNameInDomain() {{{
1682 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1683 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1684 UIImage *image([PathImages_ objectForKey:key]);
1686 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1688 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1689 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1690 image = $getImage$(path);
1691 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1692 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1696 // %hook GSFontCreateWithName() {{{
1697 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1699 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1700 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1701 name = [font UTF8String];
1702 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1703 // size *= [scale floatValue];
1704 return _GSFontCreateWithName(name, traits, size);
1708 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1709 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1711 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1713 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1715 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1716 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1718 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1721 NSString *path = [NSString stringWithUTF8String:a1];
1722 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1723 NSString *file = [path substringFromIndex:31];
1724 for (NSString *theme in Themes_) {
1725 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1726 if ([Manager_ fileExistsAtPath:path]) {
1727 strcpy(a1, [path UTF8String]);
1736 static void ChangeWallpaper(
1737 CFNotificationCenterRef center,
1741 CFDictionaryRef info
1744 NSLog(@"WB:Debug:ChangeWallpaper!");
1747 if (WallpaperFile_ != nil) {
1748 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1750 image = [image autorelease];
1753 if (WallpaperImage_ != nil)
1754 [WallpaperImage_ setImage:image];
1755 if (WallpaperPage_ != nil)
1756 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1760 #define WBRename(name, sel, imp) \
1761 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
1763 template <typename Type_>
1764 static void msset(Type_ &function, MSImageRef image, const char *name) {
1765 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1768 template <typename Type_>
1769 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1770 struct nlist &name(nl[index]);
1771 uintptr_t value(name.n_value);
1772 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1773 value |= 0x00000001;
1774 function = reinterpret_cast<Type_>(value);
1777 template <typename Type_>
1778 static void dlset(Type_ &function, const char *name) {
1779 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1782 // %hook CGImageReadCreateWithFile() {{{
1783 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1785 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1786 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1787 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1793 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
1794 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1795 if (style == nil || [style length] == 0)
1796 style = @"font-family: Helvetica; font-size: 12px";
1797 return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
1800 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
1801 if (style == nil || [style length] == 0)
1802 style = @"font-family: Helvetica; font-size: 12px";
1803 return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width];
1806 static void SBInitialize() {
1807 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
1808 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
1811 WBRename(SBApplication, pathForIcon, pathForIcon);
1812 WBRename(SBApplicationIcon, icon, icon);
1813 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1816 WBRename(SBBookmarkIcon, icon, icon);
1817 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1818 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1819 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1820 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
1822 WBRename(SBWidgetApplicationIcon, icon, icon);
1824 WBRename(SBDockIconListView, setFrame:, setFrame$);
1825 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
1827 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
1828 WBRename(SBIconLabel, setInDock:, setInDock$);
1830 WBRename(SBIconList, setFrame:, setFrame$);
1832 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
1833 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
1834 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
1835 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
1837 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
1838 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
1839 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
1841 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
1843 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
1844 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
1845 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
1846 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
1847 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
1848 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
1849 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
1850 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
1851 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
1854 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
1858 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1860 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
1861 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
1863 Manager_ = [[NSFileManager defaultManager] retain];
1864 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
1866 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
1868 // Load Settings.plist {{{
1869 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
1870 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
1871 SummerBoard_ = [value boolValue];
1872 if (NSNumber *value = [settings objectForKey:@"Debug"])
1873 Debug_ = [value boolValue];
1874 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
1875 UIDebug_ = [value boolValue];
1877 NSArray *themes([settings objectForKey:@"Themes"]);
1879 if (NSString *theme = [settings objectForKey:@"Theme"])
1880 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
1882 [NSNumber numberWithBool:true], @"Active",
1886 for (NSDictionary *theme in themes) {
1887 NSNumber *active([theme objectForKey:@"Active"]);
1888 if (![active boolValue])
1891 NSString *name([theme objectForKey:@"Name"]);
1895 NSString *theme(nil);
1897 #define testForTheme(format...) \
1898 if (theme == nil) { \
1899 NSString *path = [NSString stringWithFormat:format]; \
1900 if ([Manager_ fileExistsAtPath:path]) { \
1901 [Themes_ addObject:path]; \
1906 testForTheme(@"/Library/Themes/%@.theme", name)
1907 testForTheme(@"/Library/Themes/%@", name)
1908 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
1913 // Merge Info.plist {{{
1914 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1916 for (NSString *theme in Themes_)
1917 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
1918 for (NSString *key in [info allKeys])
1919 if ([Info_ objectForKey:key] == nil)
1920 [Info_ setObject:[info objectForKey:key] forKey:key];
1924 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
1925 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
1926 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
1929 // GraphicsServices {{{
1931 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
1935 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
1936 void *(*CGImageReadCreateWithFile)(NSString *, int);
1937 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
1938 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
1943 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
1944 Papered_ = $getTheme$(Wallpapers_) != nil;
1945 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
1947 CFNotificationCenterAddObserver(
1948 CFNotificationCenterGetDarwinNotifyCenter(),
1949 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
1952 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
1953 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
1954 if (MediaPlayer != nil)
1957 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
1958 $MPVideoView = objc_getClass("MPVideoView");
1965 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
1967 memset(nl, 0, sizeof(nl));
1968 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
1969 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
1970 nl[2].n_un.n_name = (char *) "__UIKitBundle";
1971 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
1972 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
1975 nlset(_UIApplicationImageWithName, nl, 0);
1976 nlset(_UIImageWithNameInDomain, nl, 1);
1977 nlset(_UIKitBundle, nl, 2);
1978 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
1979 nlset(_UISharedImageNameGetIdentifier, nl, 4);
1981 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
1982 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
1983 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
1987 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
1988 NSError *error(nil);
1989 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
1990 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
1992 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);