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(CKMessageCell)
126 MSClassHook(CKTimestampView)
127 MSClassHook(CKTranscriptCell)
128 MSClassHook(CKTranscriptController)
129 MSClassHook(CKTranscriptHeaderView)
130 MSClassHook(CKTranscriptTableView)
132 MSClassHook(SBApplication)
133 MSClassHook(SBApplicationIcon)
134 MSClassHook(SBAwayView)
135 MSClassHook(SBBookmarkIcon)
136 MSClassHook(SBButtonBar)
137 MSClassHook(SBCalendarApplicationIcon)
138 MSClassHook(SBCalendarIconContentsView)
139 MSClassHook(SBDockIconListView)
141 MSClassHook(SBIconBadge)
142 MSClassHook(SBIconBadgeFactory)
143 MSClassHook(SBIconController)
144 MSClassHook(SBIconLabel)
145 MSClassHook(SBIconList)
146 MSClassHook(SBIconModel)
147 //MSClassHook(SBImageCache)
148 MSClassHook(SBSearchView)
149 MSClassHook(SBSearchTableViewCell)
150 MSClassHook(SBSlidingAlertDisplay)
151 MSClassHook(SBStatusBarContentsView)
152 MSClassHook(SBStatusBarController)
153 MSClassHook(SBStatusBarOperatorNameView)
154 MSClassHook(SBStatusBarTimeView)
155 MSClassHook(SBUIController)
156 MSClassHook(SBWallpaperView)
157 MSClassHook(SBWidgetApplicationIcon)
159 extern "C" void WKSetCurrentGraphicsContext(CGContextRef);
161 __attribute__((__constructor__))
162 static void MSFixClass() {
164 $SBIcon = objc_getClass("SBIconView");
165 if ($CKTranscriptController == nil)
166 $CKTranscriptController = objc_getClass("mSMSMessageTranscriptController");
170 static bool Four_($SBDockIconListView != nil);
172 @interface NSDictionary (WinterBoard)
173 - (UIColor *) wb$colorForKey:(NSString *)key;
174 - (BOOL) wb$boolForKey:(NSString *)key;
177 @implementation NSDictionary (WinterBoard)
179 - (UIColor *) wb$colorForKey:(NSString *)key {
180 NSString *value = [self objectForKey:key];
187 - (BOOL) wb$boolForKey:(NSString *)key {
188 if (NSString *value = [self objectForKey:key])
189 return [value boolValue];
195 static BOOL (*_GSFontGetUseLegacyFontMetrics)();
196 #define $GSFontGetUseLegacyFontMetrics() \
197 (_GSFontGetUseLegacyFontMetrics == NULL ? YES : _GSFontGetUseLegacyFontMetrics())
199 static bool Debug_ = false;
200 static bool UIDebug_ = false;
201 static bool Engineer_ = false;
202 static bool SummerBoard_ = true;
203 static bool SpringBoard_;
205 static UIImage *(*_UIApplicationImageWithName)(NSString *name);
206 static UIImage *(*_UIImageWithNameInDomain)(NSString *name, NSString *domain);
207 static NSBundle *(*_UIKitBundle)();
208 static bool (*_UIPackedImageTableGetIdentifierForName)(NSString *, int *);
209 static int (*_UISharedImageNameGetIdentifier)(NSString *);
211 static NSMutableDictionary *UIImages_ = [[NSMutableDictionary alloc] initWithCapacity:32];
212 static NSMutableDictionary *PathImages_ = [[NSMutableDictionary alloc] initWithCapacity:16];
213 static NSMutableDictionary *Cache_ = [[NSMutableDictionary alloc] initWithCapacity:64];
214 static NSMutableDictionary *Strings_ = [[NSMutableDictionary alloc] initWithCapacity:0];
215 static NSMutableDictionary *Bundles_ = [[NSMutableDictionary alloc] initWithCapacity:2];
217 static NSFileManager *Manager_;
218 static NSMutableArray *Themes_;
220 static NSDictionary *English_;
221 static NSMutableDictionary *Info_;
224 static NSMutableDictionary *Themed_ = [[NSMutableDictionary alloc] initWithCapacity:128];
226 static unsigned Scale_ = 0;
228 static unsigned $getScale$(NSString *path) {
229 NSString *name(path);
231 #define StripName(strip) \
232 if ([name hasSuffix:@ strip]) \
233 name = [name substringWithRange:NSMakeRange(0, [name length] - sizeof(strip) - 1)];
237 StripName("~iphone");
240 return [name hasSuffix:@"@2x"] ? 2 : 1;
243 static NSArray *$useScale$(NSArray *files, bool use = true) {
245 UIScreen *screen([UIScreen mainScreen]);
246 if ([screen respondsToSelector:@selector(scale)])
247 Scale_ = [screen scale];
255 NSString *idiom(IsWild_ ? @"ipad" : @"iphone");
257 NSMutableArray *scaled([NSMutableArray arrayWithCapacity:([files count] * 4)]);
259 for (NSString *file in files) {
260 NSString *base([file stringByDeletingPathExtension]);
261 NSString *extension([file pathExtension]);
265 [scaled addObject:[NSString stringWithFormat:@"%@@2x~%@.%@", base, idiom, extension]];
267 [scaled addObject:[NSString stringWithFormat:@"%@@2x.%@", base, extension]];
270 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
272 // if (!IsWild_) <- support old themes
273 [scaled addObject:file];
274 } else if ([base hasSuffix: @"@2x"]) {
275 [scaled addObject:[NSString stringWithFormat:@"%@~iphone.%@", base, extension]];
276 [scaled addObject:file];
278 NSString *rest([base substringWithRange:NSMakeRange(0, [base length] - 3)]);
279 [scaled addObject:[NSString stringWithFormat:@"%@~iphone.%@", rest, extension]];
280 [scaled addObject:[rest stringByAppendingPathExtension:extension]];
282 // XXX: this code isn't really complete
284 [scaled addObject:file];
286 if ([base hasSuffix:@"~iphone"])
287 [scaled addObject:[[base substringWithRange:NSMakeRange(0, [base length] - 7)] stringByAppendingPathExtension:extension]];
294 static NSString *$getTheme$(NSArray *files, NSArray *themes = Themes_) {
295 if (NSString *path = [Themed_ objectForKey:files])
296 return reinterpret_cast<id>(path) == [NSNull null] ? nil : path;
299 NSLog(@"WB:Debug: %@", [files description]);
303 for (NSString *theme in Themes_)
304 for (NSString *file in files) {
305 path = [NSString stringWithFormat:@"%@/%@", theme, file];
306 if ([Manager_ fileExistsAtPath:path])
313 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:files];
317 // $pathForFile$inBundle$() {{{
318 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool ui) {
319 NSString *identifier = [bundle bundleIdentifier];
320 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
322 if (identifier != nil)
323 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
324 if (NSString *folder = [[bundle bundlePath] lastPathComponent])
325 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
327 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
329 #define remapResourceName(oldname, newname) \
330 else if ([file isEqualToString:(oldname)]) \
331 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
333 bool summer(SpringBoard_ && SummerBoard_);
335 if (identifier == nil);
336 else if ([identifier isEqualToString:@"com.apple.chatkit"])
337 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
338 else if ([identifier isEqualToString:@"com.apple.calculator"])
339 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
341 remapResourceName(@"FSO_BG.png", @"StatusBar")
342 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
343 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
345 if (NSString *path = $getTheme$($useScale$(names, ui)))
352 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
353 NSString *identifier = [self bundleIdentifier];
354 NSString *path = [self path];
355 NSString *folder = [path lastPathComponent];
356 NSString *dname = [self displayName];
357 NSString *didentifier = [self displayIdentifier];
360 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
362 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
364 /* XXX: I might need to keep this for backwards compatibility
365 if (identifier != nil)
366 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
368 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
370 #define testForIcon(Name) \
371 if (NSString *name = Name) \
372 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
374 if (![didentifier isEqualToString:identifier])
375 testForIcon(didentifier);
377 testForIcon(identifier);
380 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
383 if (didentifier != nil) {
384 testForIcon([English_ objectForKey:didentifier]);
386 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
387 if ([parts count] != 1)
388 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
389 testForIcon([english objectForKey:[parts lastObject]]);
392 if (NSString *path = $getTheme$(names))
398 // -[NSBundle wb$bundleWithFile] {{{
399 @interface NSBundle (WinterBoard)
400 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
403 @implementation NSBundle (WinterBoard)
405 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
406 path = [path stringByDeletingLastPathComponent];
407 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
410 NSBundle *bundle([Bundles_ objectForKey:path]);
411 if (reinterpret_cast<id>(bundle) == [NSNull null])
413 else if (bundle == nil) {
414 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
415 bundle = [NSBundle bundleWithPath:path];
417 bundle = [NSBundle wb$bundleWithFile:path];
419 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
420 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
428 // -[NSString wb$themedPath] {{{
429 @interface NSString (WinterBoard)
430 - (NSString *) wb$themedPath;
433 @implementation NSString (WinterBoard)
435 - (NSString *) wb$themedPath {
436 if ([self hasPrefix:@"/Library/Themes/"])
440 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
442 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
443 NSString *file([self stringByResolvingSymlinksInPath]);
444 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
445 if ([file hasPrefix:prefix]) {
446 NSUInteger length([prefix length]);
447 if (length != [file length])
448 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
459 void WBLogRect(const char *tag, struct CGRect rect) {
460 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
463 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
464 CGRect frame([view frame]);
465 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]);
467 for (UIView *child in [view subviews])
468 WBLogHierarchy(child, index++, indent + 1);
471 UIImage *$cacheForImage$(UIImage *image) {
472 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
473 CGRect rect = {CGPointMake(1, 1), [image size]};
474 CGSize size = {rect.size.width + 2, rect.size.height + 2};
476 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
477 CGColorSpaceRelease(space);
479 CGContextDrawImage(context, rect, [image CGImage]);
480 CGImageRef ref(CGBitmapContextCreateImage(context));
481 CGContextRelease(context);
483 UIImage *cache([UIImage imageWithCGImage:ref]);
489 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
490 //if ([name isEqualToString:@"icons"]) return nil;
491 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
494 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
495 NSString *key([icon displayIdentifier]);
497 if (UIImage *image = [icon icon]) {
498 CGSize size = [image size];
499 if (size.width != 59 || size.height != 60) {
500 UIImage *cache($cacheForImage$(image));
501 [Cache_ setObject:cache forKey:key];
506 _SBIconModel$cacheImageForIcon$(self, sel, icon);
509 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
510 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
511 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
513 NSString *key([icon displayIdentifier]);
515 if (UIImage *image = [icon icon]) {
516 CGSize size = [image size];
517 if (size.width != 59 || size.height != 60) {
518 UIImage *cache($cacheForImage$(image));
519 [Cache_ setObject:cache forKey:key];
525 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
526 NSString *key([icon displayIdentifier]);
527 if (UIImage *image = [Cache_ objectForKey:key])
530 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
533 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
535 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
536 NSString *key([icon displayIdentifier]);
537 if (UIImage *image = [Cache_ objectForKey:key])
540 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
543 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
544 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
545 [self setBackgroundColor:[UIColor clearColor]];
546 for (UIView *child in [self subviews])
547 [child setBackgroundColor:[UIColor clearColor]];
551 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
552 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
553 [self setBackgroundColor:[UIColor clearColor]];
557 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
558 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
559 float inset([self edgeInset]);
560 [[UIColor clearColor] set];
561 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
562 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
565 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
566 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
567 if (NSString *path = $pathForIcon$([self application]))
568 return [UIImage imageWithContentsOfFile:path];
569 return _SBApplicationIcon$icon(self, sel);
572 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
574 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
575 if (IsWild_ && false) // XXX: delete this code, it should not be supported
576 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
577 return [UIImage imageWithContentsOfFile:path72];
578 if (NSString *path = $pathForIcon$([self application]))
579 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
581 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
582 width = [$SBIcon defaultIconImageSize].width;
585 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
588 return _SBApplicationIcon$generateIconImage$(self, sel, type);
591 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
593 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
594 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
595 return [UIImage imageWithContentsOfFile:path];
596 return _SBWidgetApplicationIcon$icon(self, sel);
599 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
601 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
602 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
603 return [UIImage imageWithContentsOfFile:path];
604 return _SBBookmarkIcon$icon(self, sel);
607 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
608 if (NSString *path = $pathForIcon$(self))
610 return _SBApplication$pathForIcon(self, sel);
613 static UIImage *CachedImageAtPath(NSString *path) {
614 path = [path stringByResolvingSymlinksInPath];
615 UIImage *image = [PathImages_ objectForKey:path];
617 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
618 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
620 image = [image autorelease];
621 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
625 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
626 NSBundle *bundle = [NSBundle mainBundle];
628 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
629 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
630 return CachedImageAtPath(path);
631 return __UIApplicationImageWithName(name);
634 #define WBDelegate(delegate) \
635 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
637 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
638 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
640 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
644 - (void) forwardInvocation:(NSInvocation*)inv { \
645 SEL sel = [inv selector]; \
646 if ([delegate respondsToSelector:sel]) \
647 [inv invokeWithTarget:delegate]; \
649 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
652 // %hook -[NSBundle pathForResource:ofType:] {{{
653 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
654 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
656 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
657 if (NSString *path = $pathForFile$inBundle$(file, self, false))
659 return MSOldCall(resource, type);
663 static struct WBStringDrawingState {
664 WBStringDrawingState *next_;
668 } *stringDrawingState_;
670 MSInstanceMessageHook4(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode, CGPoint, point, float, width, UIFont *, font, int, mode) {
671 WBStringDrawingState *state(stringDrawingState_);
673 return MSOldCall(point, width, font, mode);
675 if (--state->count_ == 0)
676 stringDrawingState_ = state->next_;
677 if (state->info_ == nil)
678 return MSOldCall(point, width, font, mode);
680 NSString *info([Info_ objectForKey:state->info_]);
682 return MSOldCall(point, width, font, mode);
684 NSString *base(state->base_ ?: @"");
685 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]];
689 MSInstanceMessageHook2(CGSize, NSString, drawAtPoint,withFont, CGPoint, point, UIFont *, font) {
690 WBStringDrawingState *state(stringDrawingState_);
692 return MSOldCall(point, font);
694 if (--state->count_ == 0)
695 stringDrawingState_ = state->next_;
696 if (state->info_ == nil)
697 return MSOldCall(point, font);
699 NSString *info([Info_ objectForKey:state->info_]);
701 return MSOldCall(point, font);
703 NSString *base(state->base_ ?: @"");
704 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]];
708 MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) {
709 WBStringDrawingState *state(stringDrawingState_);
711 return MSOldCall(font);
713 if (--state->count_ == 0)
714 stringDrawingState_ = state->next_;
715 if (state->info_ == nil)
716 return MSOldCall(font);
718 NSString *info([Info_ objectForKey:state->info_]);
720 return MSOldCall(font);
722 NSString *base(state->base_ ?: @"");
723 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info] forWidth:65535];
726 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
727 WBStringDrawingState badgeState = {NULL, 1, @""
731 stringDrawingState_ = &badgeState;
733 UIImage *image(MSOldCall(text));
735 stringDrawingState_ = NULL;
739 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
740 WBStringDrawingState dayState = {NULL, 2, @""
742 // XXX: this is only correct on an iPod dock
743 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
744 , @"CalendarIconDayStyle"};
746 WBStringDrawingState sizeState = {&dayState, 7, nil, nil};
748 WBStringDrawingState dateState = {&sizeState, 2, @""
750 , @"CalendarIconDateStyle"};
752 stringDrawingState_ = &dateState;
754 UIImage *image(MSOldCall(type));
756 stringDrawingState_ = NULL;
760 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
761 NSBundle *bundle([NSBundle mainBundle]);
763 CFLocaleRef locale(CFLocaleCopyCurrent());
764 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
767 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
769 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
770 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
771 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
772 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
776 CFRelease(formatter);
778 NSString *datestyle([@""
779 "font-family: Helvetica; "
780 "font-weight: bold; "
783 "" stringByAppendingString:(IsWild_
784 ? @"font-size: 54px; "
785 : @"font-size: 39px; "
788 NSString *daystyle([@""
789 "font-family: Helvetica; "
790 "font-weight: bold; "
792 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
793 "" stringByAppendingString:(IsWild_
794 ? @"font-size: 11px; "
795 : @"font-size: 9px; "
798 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
799 datestyle = [datestyle stringByAppendingString:style];
800 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
801 daystyle = [daystyle stringByAppendingString:style];
803 float width([self bounds].size.width);
805 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
806 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
808 unsigned base0(IsWild_ ? 89 : 70);
809 if ($GSFontGetUseLegacyFontMetrics())
811 unsigned base1(IsWild_ ? 18 : 16);
818 [(NSString *)date drawAtPoint:CGPointMake(
819 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
820 ) withStyle:datestyle];
822 [(NSString *)day drawAtPoint:CGPointMake(
823 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
824 ) withStyle:daystyle];
830 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
831 void $setBarStyle$_(NSString *name, int &style) {
833 NSLog(@"WB:Debug:%@Style:%d", name, style);
834 NSNumber *number = nil;
836 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
838 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
840 style = [number intValue];
842 NSLog(@"WB:Debug:%@Style=%d", name, style);
846 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
847 $setBarStyle$_(@"Toolbar", style);
848 return MSOldCall(style);
851 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
852 $setBarStyle$_(@"NavigationBar", style);
853 return MSOldCall(style);
857 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
858 [[self superview] setBackgroundColor:[UIColor clearColor]];
859 _SBButtonBar$didMoveToSuperview(self, sel);
862 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
863 [[self superview] setBackgroundColor:[UIColor clearColor]];
864 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
867 static NSArray *Wallpapers_;
868 static bool Papered_;
870 static NSString *WallpaperFile_;
871 static UIImageView *WallpaperImage_;
872 static UIWebDocumentView *WallpaperPage_;
873 static NSURL *WallpaperURL_;
875 #define _release(object) \
876 do if (object != nil) { \
881 static UIImage *$getImage$(NSString *path) {
882 UIImage *image([UIImage imageWithContentsOfFile:path]);
884 unsigned scale($getScale$(path));
885 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
886 [image setScale:scale];
891 static UIImage *$getDefaultDesktopImage$() {
892 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
893 return $getImage$(path);
897 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
898 return $getDefaultDesktopImage$() ?: MSOldCall();
901 MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
902 return $getDefaultDesktopImage$() ?: MSOldCall();
905 MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
906 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
907 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
908 if (UIImage *image = $getDefaultDesktopImage$()) {
909 [self setImage:image];
919 // %hook -[SBUIController init] {{{
920 MSInstanceMessageHook0(id, SBUIController, init) {
925 NSString *paper($getTheme$(Wallpapers_));
927 paper = [paper stringByDeletingLastPathComponent];
931 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
932 char *machine = new char[size];
934 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
935 perror("sysctlbyname(\"hw.machine\", ?)");
940 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
944 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
947 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
948 if (&_wallpaperView != NULL) {
949 [_wallpaperView removeFromSuperview];
950 [_wallpaperView release];
951 _wallpaperView = nil;
955 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
956 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
959 if (&_contentLayer != NULL)
960 player = &_contentLayer;
961 else if (&_contentView != NULL)
962 player = &_contentView;
965 UIView *layer(player == NULL ? nil : *player);
967 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
968 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
969 [window setContentView:content];
971 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
972 [window setBackgroundColor:[_window backgroundColor]];
973 [_window setBackgroundColor:[UIColor clearColor]];
975 [window setLevel:-1000];
976 [window setHidden:NO];
978 /*if (player != NULL)
981 [content setBackgroundColor:[layer backgroundColor]];
982 [layer setBackgroundColor:[UIColor clearColor]];
985 if (!SummerBoard_ || !IsWild_)
988 CGRect bounds([content bounds]);
989 bounds.origin.y = -30;
990 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
991 [content addSubview:indirect];
992 [indirect zoomToScale:2.4];
995 _release(WallpaperFile_);
996 _release(WallpaperImage_);
997 _release(WallpaperPage_);
998 _release(WallpaperURL_);
1001 NSArray *themes([NSArray arrayWithObject:paper]);
1003 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1007 static AVController *controller_(nil);
1008 if (controller_ == nil) {
1009 AVQueue *queue([AVQueue avQueue]);
1010 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1013 AVQueue *queue([controller_ queue]);
1015 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1016 [controller_ setLayer:[video _layer]];
1018 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1019 [queue appendItem:item error:&error];
1021 [controller_ play:&error];
1022 #elif UseMPMoviePlayerController
1023 NSURL *url([NSURL fileURLWithPath:path]);
1024 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1025 controller.movieControlMode = MPMovieControlModeHidden;
1028 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1029 [video setMovieWithPath:path];
1030 [video setRepeatMode:1];
1031 [video setRepeatGap:-1];
1032 [video playFromBeginning];;
1035 [indirect addSubview:video];
1038 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1039 if (UIImage *image = $getImage$(path)) {
1040 WallpaperFile_ = [path retain];
1041 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1042 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1043 [WallpaperImage_ setAlpha:[number floatValue]];
1044 [indirect addSubview:WallpaperImage_];
1048 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1049 CGRect bounds = [indirect bounds];
1051 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1052 [view setAutoresizes:true];
1054 WallpaperPage_ = [view retain];
1055 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1057 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1059 [view setBackgroundColor:[UIColor clearColor]];
1060 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1061 [view setDrawsBackground:NO];
1062 [[view webView] setDrawsBackground:NO];
1064 [indirect addSubview:view];
1068 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1069 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1070 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1071 if ([Manager_ fileExistsAtPath:html]) {
1072 CGRect bounds = [indirect bounds];
1074 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1075 [view setAutoresizes:true];
1077 NSURL *url = [NSURL fileURLWithPath:html];
1078 [view loadRequest:[NSURLRequest requestWithURL:url]];
1080 [view setBackgroundColor:[UIColor clearColor]];
1081 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1082 [view setDrawsBackground:NO];
1083 [[view webView] setDrawsBackground:NO];
1085 [indirect addSubview:view];
1093 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1094 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1095 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1097 if (path != nil && _backgroundView != nil)
1100 _SBAwayView$updateDesktopImage$(self, sel, image);
1103 CGRect bounds = [self bounds];
1105 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1106 [view setAutoresizes:true];
1108 if (WallpaperPage_ != nil)
1109 [WallpaperPage_ release];
1110 WallpaperPage_ = [view retain];
1112 if (WallpaperURL_ != nil)
1113 [WallpaperURL_ release];
1114 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1116 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1118 [[view webView] setDrawsBackground:false];
1119 [view setBackgroundColor:[UIColor clearColor]];
1121 [self insertSubview:view aboveSubview:_backgroundView];
1125 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1126 extern "C" CGColorRef CGGStateGetFillColor(void *);
1127 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1128 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1130 /* WBTimeLabel {{{ */
1131 @interface WBTimeLabel : NSProxy {
1133 _transient SBStatusBarTimeView *view_;
1136 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1140 @implementation WBTimeLabel
1147 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1148 time_ = [time retain];
1153 - (NSString *) description {
1159 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1160 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1161 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1163 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1164 "font-family: Helvetica; "
1165 "font-weight: bold; "
1168 "%@", _mode ? @"white" : @"black", custom]];
1173 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1178 /* WBBadgeLabel {{{ */
1179 @interface WBBadgeLabel : NSProxy {
1183 - (id) initWithBadge:(NSString *)badge;
1184 - (NSString *) description;
1188 @implementation WBBadgeLabel
1195 - (id) initWithBadge:(NSString *)badge {
1196 badge_ = [badge retain];
1200 - (NSString *) description {
1201 return [badge_ description];
1206 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1207 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1208 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1209 "font-family: Helvetica; "
1210 "font-weight: bold; "
1218 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1225 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1226 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1227 alpha = [number floatValue];
1228 return MSOldCall(alpha);
1231 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1232 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1233 alpha = [number floatValue];
1234 return MSOldCall(alpha);
1237 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1238 if ((self = MSOldCall()) != nil) {
1239 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1240 // XXX: note: this is overridden above, which is silly
1241 float alpha([number floatValue]);
1242 [self setIconImageAlpha:alpha];
1243 [self setIconLabelAlpha:alpha];
1248 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1249 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1250 alpha = [number floatValue];
1251 return MSOldCall(alpha);
1255 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1256 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1257 id &_badge(MSHookIvar<id>(self, "_badge"));
1259 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1264 void SBStatusBarController$setStatusBarMode(int &mode) {
1266 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1267 if (mode < 100) // 104:hidden 105:glowing
1268 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1269 mode = [number intValue];
1272 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1273 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1274 SBStatusBarController$setStatusBarMode(mode);
1275 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1278 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1279 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1280 SBStatusBarController$setStatusBarMode(mode);
1281 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1284 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) {
1285 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1286 SBStatusBarController$setStatusBarMode(mode);
1287 //NSLog(@"mode=%u", mode);
1288 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1291 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1292 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1293 mode = [number intValue];
1294 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1297 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1298 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1300 NSLog(@"operatorNameStyle= %@", style);
1301 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1302 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1306 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1308 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1309 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1312 // XXX: replace this with [SBStatusBarTimeView tile]
1313 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1314 id &_time(MSHookIvar<id>(self, "_time"));
1315 if (_time != nil && [_time class] != [WBTimeLabel class])
1316 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1317 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1320 @interface UIView (WinterBoard)
1321 - (bool) wb$isWBImageView;
1322 - (void) wb$logHierarchy;
1323 - (void) wb$setBackgroundColor:(UIColor *)color;
1326 @implementation UIView (WinterBoard)
1328 - (bool) wb$isWBImageView {
1332 - (void) wb$logHierarchy {
1333 WBLogHierarchy(self);
1336 - (void) wb$setBackgroundColor:(UIColor *)color {
1337 [self setBackgroundColor:color];
1338 for (UIView *child in [self subviews])
1339 [child wb$setBackgroundColor:color];
1344 @interface WBImageView : UIImageView {
1347 - (bool) wb$isWBImageView;
1348 - (void) wb$updateFrame;
1351 @implementation WBImageView
1353 - (bool) wb$isWBImageView {
1357 - (void) wb$updateFrame {
1358 CGRect frame([self frame]);
1361 for (UIView *view(self); ; ) {
1362 view = [view superview];
1365 frame.origin.y -= [view frame].origin.y;
1368 [self setFrame:frame];
1373 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1374 NSArray *subviews([self subviews]);
1375 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1376 if (view != nil && [view wb$isWBImageView])
1377 [view wb$updateFrame];
1378 _SBIconList$setFrame$(self, sel, frame);
1381 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1382 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1383 NSArray *lists([_iconModel iconLists]);
1385 for (unsigned i(0), e([lists count]); i != e; ++i)
1386 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]])) {
1387 SBIconList *list([lists objectAtIndex:i]);
1388 NSArray *subviews([list subviews]);
1390 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1391 if (view == nil || ![view wb$isWBImageView]) {
1392 view = [[[WBImageView alloc] init] autorelease];
1393 [list insertSubview:view atIndex:0];
1396 UIImage *image([UIImage imageWithContentsOfFile:path]);
1398 CGRect frame([view frame]);
1399 frame.size = [image size];
1400 [view setFrame:frame];
1402 [view setImage:image];
1403 [view wb$updateFrame];
1406 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1409 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1410 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1412 [self setClipsToBounds:NO];
1416 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1417 static bool gssc(false);
1419 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1420 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1423 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1424 [Info_ setObject:[NSNumber numberWithBool:(
1426 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1427 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1428 )] forKey:@"UndockedIconLabels"];
1431 id &_label(MSHookIvar<id>(self, "_label"));
1432 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1435 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1436 [_label setInDock:docked];
1438 _SBIconLabel$setInDock$(self, sel, docked);
1439 [self setNeedsDisplay];
1442 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1443 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1446 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1447 _SBDockIconListView$setFrame$(self, sel, frame);
1450 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1451 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1452 NSString *identifier = [self bundleIdentifier];
1453 NSLocale *locale = [NSLocale currentLocale];
1454 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1456 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1457 NSString *file = table == nil ? @"Localizable" : table;
1458 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1459 NSDictionary *strings;
1460 if ((strings = [Strings_ objectForKey:name]) != nil) {
1461 if (static_cast<id>(strings) != [NSNull null]) strings:
1462 if (NSString *value = [strings objectForKey:key])
1464 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1467 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1468 [Strings_ setObject:[strings autorelease] forKey:name];
1472 [Strings_ setObject:[NSNull null] forKey:name];
1473 return MSOldCall(key, value, table);
1476 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1477 MSClassHook(WebCoreFrameBridge)
1479 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1482 void **core(reinterpret_cast<void **>([node _node]));
1483 if (core == NULL || core[6] == NULL)
1485 return MSOldCall(node, width);
1489 MSInstanceMessageHook1(void, SBIconLabel, drawRect, CGRect, rect) {
1490 CGRect bounds = [self bounds];
1492 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1495 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1496 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1498 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1500 NSString *style = [NSString stringWithFormat:@""
1501 "font-family: Helvetica; "
1502 "font-weight: bold; "
1504 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1505 ? @"font-size: 12px; "
1506 : @"font-size: 11px; "
1510 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1512 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1514 bool ellipsis(false);
1515 float max = [self frame].size.width - 11, width;
1517 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
1520 size_t length([label length]);
1521 float spacing((width - max) / (length - 1));
1523 if (spacing > 1.25) {
1525 label = [label substringToIndex:(length - 1)];
1529 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
1533 label = [label stringByAppendingString:@"..."];
1535 if (NSString *custom = [Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")])
1536 style = [style stringByAppendingString:custom];
1538 CGSize size = [label sizeWithStyle:style forWidth:bounds.size.width];
1539 [label drawAtPoint:CGPointMake((bounds.size.width - size.width) / 2, 0) withStyle:style];
1543 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1544 [self wb$setBackgroundColor:[UIColor clearColor]];
1548 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1550 [balloon setBackgroundColor:[UIColor clearColor]];
1553 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1554 MSOldCall([UIColor clearColor]);
1555 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1559 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1560 if ((self = MSOldCall(style, reuse)) != nil) {
1561 [self setBackgroundColor:[UIColor clearColor]];
1562 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1567 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1568 if ((self = MSOldCall(style, reuse)) != nil) {
1569 [self setBackgroundColor:[UIColor clearColor]];
1570 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1574 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1575 if ((self = MSOldCall(style, reuse)) != nil) {
1576 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1577 [_label setBackgroundColor:[UIColor clearColor]];
1581 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1582 MSOldCall(UITableViewCellSeparatorStyleNone);
1585 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1586 if ((self = MSOldCall(frame, style)) != nil) {
1587 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1591 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1594 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1595 if (UIImage *image = $getImage$(path)) {
1596 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1597 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1599 if (&_transcriptTable != NULL)
1600 table = _transcriptTable;
1601 else if (&_transcriptLayer != NULL)
1602 table = _transcriptLayer;
1606 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1607 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1610 [placard insertSubview:background atIndex:0];
1612 [table setBackgroundColor:[UIColor clearColor]];
1613 [placard insertSubview:background belowSubview:table];
1619 // %hook _UIImageWithName() {{{
1620 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1622 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1629 if (_UIPackedImageTableGetIdentifierForName != NULL)
1630 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1631 else if (_UISharedImageNameGetIdentifier != NULL) {
1632 identifier = _UISharedImageNameGetIdentifier(name);
1633 packed = identifier != -1;
1640 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1643 return __UIImageWithName(name);
1645 NSNumber *key([NSNumber numberWithInt:identifier]);
1646 UIImage *image([UIImages_ objectForKey:key]);
1648 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1649 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1650 image = $getImage$(path);
1651 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1655 image = __UIImageWithName(name);
1658 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1659 if (![Manager_ fileExistsAtPath:path])
1660 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1667 // %hook _UIImageWithNameInDomain() {{{
1668 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1669 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1670 UIImage *image([PathImages_ objectForKey:key]);
1672 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1674 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1675 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1676 image = $getImage$(path);
1677 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1678 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1682 // %hook GSFontCreateWithName() {{{
1683 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1685 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1686 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1687 name = [font UTF8String];
1688 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1689 // size *= [scale floatValue];
1690 return _GSFontCreateWithName(name, traits, size);
1694 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1695 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1697 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1699 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1701 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1702 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1704 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1707 NSString *path = [NSString stringWithUTF8String:a1];
1708 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1709 NSString *file = [path substringFromIndex:31];
1710 for (NSString *theme in Themes_) {
1711 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1712 if ([Manager_ fileExistsAtPath:path]) {
1713 strcpy(a1, [path UTF8String]);
1722 static void ChangeWallpaper(
1723 CFNotificationCenterRef center,
1727 CFDictionaryRef info
1730 NSLog(@"WB:Debug:ChangeWallpaper!");
1733 if (WallpaperFile_ != nil) {
1734 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1736 image = [image autorelease];
1739 if (WallpaperImage_ != nil)
1740 [WallpaperImage_ setImage:image];
1741 if (WallpaperPage_ != nil)
1742 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1746 #define WBRename(name, sel, imp) \
1747 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
1749 template <typename Type_>
1750 static void msset(Type_ &function, MSImageRef image, const char *name) {
1751 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1754 template <typename Type_>
1755 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1756 struct nlist &name(nl[index]);
1757 uintptr_t value(name.n_value);
1758 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1759 value |= 0x00000001;
1760 function = reinterpret_cast<Type_>(value);
1763 template <typename Type_>
1764 static void dlset(Type_ &function, const char *name) {
1765 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1768 // %hook CGImageReadCreateWithFile() {{{
1769 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1771 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1772 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1773 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1779 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
1780 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1781 if (style == nil || [style length] == 0)
1782 style = @"font-family: Helvetica; font-size: 12px";
1783 return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
1786 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
1787 if (style == nil || [style length] == 0)
1788 style = @"font-family: Helvetica; font-size: 12px";
1789 return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width];
1792 static void SBInitialize() {
1793 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
1794 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
1797 WBRename(SBApplication, pathForIcon, pathForIcon);
1798 WBRename(SBApplicationIcon, icon, icon);
1799 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1802 WBRename(SBBookmarkIcon, icon, icon);
1803 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1804 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1805 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1806 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
1808 WBRename(SBWidgetApplicationIcon, icon, icon);
1810 WBRename(SBDockIconListView, setFrame:, setFrame$);
1811 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
1813 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
1814 WBRename(SBIconLabel, setInDock:, setInDock$);
1816 WBRename(SBIconList, setFrame:, setFrame$);
1818 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
1819 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
1820 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
1821 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
1823 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
1824 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
1825 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
1827 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
1829 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
1830 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
1831 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
1832 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
1833 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
1834 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
1835 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
1836 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
1837 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
1840 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
1844 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1846 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
1847 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
1849 Manager_ = [[NSFileManager defaultManager] retain];
1850 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
1852 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
1854 // Load Settings.plist {{{
1855 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
1856 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
1857 SummerBoard_ = [value boolValue];
1858 if (NSNumber *value = [settings objectForKey:@"Debug"])
1859 Debug_ = [value boolValue];
1860 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
1861 UIDebug_ = [value boolValue];
1863 NSArray *themes([settings objectForKey:@"Themes"]);
1865 if (NSString *theme = [settings objectForKey:@"Theme"])
1866 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
1868 [NSNumber numberWithBool:true], @"Active",
1872 for (NSDictionary *theme in themes) {
1873 NSNumber *active([theme objectForKey:@"Active"]);
1874 if (![active boolValue])
1877 NSString *name([theme objectForKey:@"Name"]);
1881 NSString *theme(nil);
1883 #define testForTheme(format...) \
1884 if (theme == nil) { \
1885 NSString *path = [NSString stringWithFormat:format]; \
1886 if ([Manager_ fileExistsAtPath:path]) { \
1887 [Themes_ addObject:path]; \
1892 testForTheme(@"/Library/Themes/%@.theme", name)
1893 testForTheme(@"/Library/Themes/%@", name)
1894 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
1899 // Merge Info.plist {{{
1900 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1902 for (NSString *theme in Themes_)
1903 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
1904 for (NSString *key in [info allKeys])
1905 if ([Info_ objectForKey:key] == nil)
1906 [Info_ setObject:[info objectForKey:key] forKey:key];
1910 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
1911 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
1912 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
1915 // GraphicsServices {{{
1917 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
1921 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
1922 void *(*CGImageReadCreateWithFile)(NSString *, int);
1923 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
1924 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
1929 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
1930 Papered_ = $getTheme$(Wallpapers_) != nil;
1931 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]);
1933 CFNotificationCenterAddObserver(
1934 CFNotificationCenterGetDarwinNotifyCenter(),
1935 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
1938 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
1939 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
1940 if (MediaPlayer != nil)
1943 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
1944 $MPVideoView = objc_getClass("MPVideoView");
1951 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
1953 memset(nl, 0, sizeof(nl));
1954 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
1955 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
1956 nl[2].n_un.n_name = (char *) "__UIKitBundle";
1957 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
1958 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
1961 nlset(_UIApplicationImageWithName, nl, 0);
1962 nlset(_UIImageWithNameInDomain, nl, 1);
1963 nlset(_UIKitBundle, nl, 2);
1964 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
1965 nlset(_UISharedImageNameGetIdentifier, nl, 4);
1967 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
1968 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
1969 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
1973 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
1974 NSError *error(nil);
1975 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
1976 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
1978 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);