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]:_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(CKTranscriptTableView)
131 MSClassHook(SBApplication)
132 MSClassHook(SBApplicationIcon)
133 MSClassHook(SBAwayView)
134 MSClassHook(SBBookmarkIcon)
135 MSClassHook(SBButtonBar)
136 MSClassHook(SBCalendarApplicationIcon)
137 MSClassHook(SBCalendarIconContentsView)
138 MSClassHook(SBDockIconListView)
140 MSClassHook(SBIconBadge)
141 MSClassHook(SBIconBadgeFactory)
142 MSClassHook(SBIconController)
143 MSClassHook(SBIconLabel)
144 MSClassHook(SBIconList)
145 MSClassHook(SBIconModel)
146 //MSClassHook(SBImageCache)
147 MSClassHook(SBSearchView)
148 MSClassHook(SBSearchTableViewCell)
149 MSClassHook(SBSlidingAlertDisplay)
150 MSClassHook(SBStatusBarContentsView)
151 MSClassHook(SBStatusBarController)
152 MSClassHook(SBStatusBarOperatorNameView)
153 MSClassHook(SBStatusBarTimeView)
154 MSClassHook(SBUIController)
155 MSClassHook(SBWallpaperView)
156 MSClassHook(SBWidgetApplicationIcon)
158 extern "C" void WKSetCurrentGraphicsContext(CGContextRef);
160 __attribute__((__constructor__))
161 static void MSFixClass() {
163 $SBIcon = objc_getClass("SBIconView");
164 if ($CKTranscriptController == nil)
165 $CKTranscriptController = objc_getClass("mSMSMessageTranscriptController");
169 static bool Four_($SBDockIconListView != nil);
171 @interface NSDictionary (WinterBoard)
172 - (UIColor *) wb$colorForKey:(NSString *)key;
173 - (BOOL) wb$boolForKey:(NSString *)key;
176 @implementation NSDictionary (WinterBoard)
178 - (UIColor *) wb$colorForKey:(NSString *)key {
179 NSString *value = [self objectForKey:key];
186 - (BOOL) wb$boolForKey:(NSString *)key {
187 if (NSString *value = [self objectForKey:key])
188 return [value boolValue];
194 static BOOL (*_GSFontGetUseLegacyFontMetrics)();
195 #define $GSFontGetUseLegacyFontMetrics() \
196 (_GSFontGetUseLegacyFontMetrics == NULL ? YES : _GSFontGetUseLegacyFontMetrics())
198 static bool Debug_ = false;
199 static bool UIDebug_ = false;
200 static bool Engineer_ = false;
201 static bool SummerBoard_ = true;
202 static bool SpringBoard_;
204 static UIImage *(*_UIApplicationImageWithName)(NSString *name);
205 static UIImage *(*_UIImageWithNameInDomain)(NSString *name, NSString *domain);
206 static NSBundle *(*_UIKitBundle)();
207 static bool (*_UIPackedImageTableGetIdentifierForName)(NSString *, int *);
208 static int (*_UISharedImageNameGetIdentifier)(NSString *);
210 static NSMutableDictionary *UIImages_ = [[NSMutableDictionary alloc] initWithCapacity:32];
211 static NSMutableDictionary *PathImages_ = [[NSMutableDictionary alloc] initWithCapacity:16];
212 static NSMutableDictionary *Cache_ = [[NSMutableDictionary alloc] initWithCapacity:64];
213 static NSMutableDictionary *Strings_ = [[NSMutableDictionary alloc] initWithCapacity:0];
214 static NSMutableDictionary *Bundles_ = [[NSMutableDictionary alloc] initWithCapacity:2];
216 static NSFileManager *Manager_;
217 static NSMutableArray *Themes_;
219 static NSDictionary *English_;
220 static NSMutableDictionary *Info_;
223 static NSMutableDictionary *Themed_ = [[NSMutableDictionary alloc] initWithCapacity:128];
225 static unsigned Scale_ = 0;
227 static unsigned $getScale$(NSString *path) {
228 NSString *name(path);
230 #define StripName(strip) \
231 if ([name hasSuffix:@ strip]) \
232 name = [name substringWithRange:NSMakeRange(0, [name length] - sizeof(strip) - 1)];
236 StripName("~iphone");
239 return [name hasSuffix:@"@2x"] ? 2 : 1;
242 static NSArray *$useScale$(NSArray *files, bool use = true) {
244 UIScreen *screen([UIScreen mainScreen]);
245 if ([screen respondsToSelector:@selector(scale)])
246 Scale_ = [screen scale];
254 NSString *idiom(IsWild_ ? @"ipad" : @"iphone");
256 NSMutableArray *scaled([NSMutableArray arrayWithCapacity:([files count] * 4)]);
258 for (NSString *file in files) {
259 NSString *base([file stringByDeletingPathExtension]);
260 NSString *extension([file pathExtension]);
264 [scaled addObject:[NSString stringWithFormat:@"%@@2x~%@.%@", base, idiom, extension]];
266 [scaled addObject:[NSString stringWithFormat:@"%@@2x.%@", base, extension]];
269 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
271 // if (!IsWild_) <- support old themes
272 [scaled addObject:file];
273 } else if ([base hasSuffix: @"@2x"]) {
274 [scaled addObject:[NSString stringWithFormat:@"%@~iphone.%@", base, extension]];
275 [scaled addObject:file];
277 NSString *rest([base substringWithRange:NSMakeRange(0, [base length] - 3)]);
278 [scaled addObject:[NSString stringWithFormat:@"%@~iphone.%@", rest, extension]];
279 [scaled addObject:[rest stringByAppendingPathExtension:extension]];
281 // XXX: this code isn't really complete
283 [scaled addObject:file];
285 if ([base hasSuffix:@"~iphone"])
286 [scaled addObject:[[base substringWithRange:NSMakeRange(0, [base length] - 7)] stringByAppendingPathExtension:extension]];
293 static NSString *$getTheme$(NSArray *files, NSArray *themes = Themes_) {
294 if (NSString *path = [Themed_ objectForKey:files])
295 return reinterpret_cast<id>(path) == [NSNull null] ? nil : path;
298 NSLog(@"WB:Debug: %@", [files description]);
302 for (NSString *theme in Themes_)
303 for (NSString *file in files) {
304 path = [NSString stringWithFormat:@"%@/%@", theme, file];
305 if ([Manager_ fileExistsAtPath:path])
312 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:files];
316 // $pathForFile$inBundle$() {{{
317 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool ui) {
318 NSString *identifier = [bundle bundleIdentifier];
319 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
321 if (identifier != nil)
322 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
323 if (NSString *folder = [[bundle bundlePath] lastPathComponent])
324 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
326 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
328 #define remapResourceName(oldname, newname) \
329 else if ([file isEqualToString:(oldname)]) \
330 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
332 bool summer(SpringBoard_ && SummerBoard_);
334 if (identifier == nil);
335 else if ([identifier isEqualToString:@"com.apple.chatkit"])
336 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
337 else if ([identifier isEqualToString:@"com.apple.calculator"])
338 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
340 remapResourceName(@"FSO_BG.png", @"StatusBar")
341 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
342 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
344 if (NSString *path = $getTheme$($useScale$(names, ui)))
351 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
352 NSString *identifier = [self bundleIdentifier];
353 NSString *path = [self path];
354 NSString *folder = [path lastPathComponent];
355 NSString *dname = [self displayName];
356 NSString *didentifier = [self displayIdentifier];
359 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
361 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
363 /* XXX: I might need to keep this for backwards compatibility
364 if (identifier != nil)
365 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
367 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
369 #define testForIcon(Name) \
370 if (NSString *name = Name) \
371 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
373 if (![didentifier isEqualToString:identifier])
374 testForIcon(didentifier);
376 testForIcon(identifier);
379 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
382 if (didentifier != nil) {
383 testForIcon([English_ objectForKey:didentifier]);
385 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
386 if ([parts count] != 1)
387 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
388 testForIcon([english objectForKey:[parts lastObject]]);
391 if (NSString *path = $getTheme$(names))
397 // -[NSBundle wb$bundleWithFile] {{{
398 @interface NSBundle (WinterBoard)
399 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
402 @implementation NSBundle (WinterBoard)
404 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
405 path = [path stringByDeletingLastPathComponent];
406 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
409 NSBundle *bundle([Bundles_ objectForKey:path]);
410 if (reinterpret_cast<id>(bundle) == [NSNull null])
412 else if (bundle == nil) {
413 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
414 bundle = [NSBundle bundleWithPath:path];
416 bundle = [NSBundle wb$bundleWithFile:path];
418 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
419 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
427 // -[NSString wb$themedPath] {{{
428 @interface NSString (WinterBoard)
429 - (NSString *) wb$themedPath;
432 @implementation NSString (WinterBoard)
434 - (NSString *) wb$themedPath {
435 if ([self hasPrefix:@"/Library/Themes/"])
439 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
441 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
442 NSString *file([self stringByResolvingSymlinksInPath]);
443 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
444 if ([file hasPrefix:prefix]) {
445 NSUInteger length([prefix length]);
446 if (length != [file length])
447 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
458 void WBLogRect(const char *tag, struct CGRect rect) {
459 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
462 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
463 CGRect frame([view frame]);
464 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]);
466 for (UIView *child in [view subviews])
467 WBLogHierarchy(child, index++, indent + 1);
470 UIImage *$cacheForImage$(UIImage *image) {
471 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
472 CGRect rect = {CGPointMake(1, 1), [image size]};
473 CGSize size = {rect.size.width + 2, rect.size.height + 2};
475 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
476 CGColorSpaceRelease(space);
478 CGContextDrawImage(context, rect, [image CGImage]);
479 CGImageRef ref(CGBitmapContextCreateImage(context));
480 CGContextRelease(context);
482 UIImage *cache([UIImage imageWithCGImage:ref]);
488 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
489 //if ([name isEqualToString:@"icons"]) return nil;
490 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
493 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
494 NSString *key([icon displayIdentifier]);
496 if (UIImage *image = [icon icon]) {
497 CGSize size = [image size];
498 if (size.width != 59 || size.height != 60) {
499 UIImage *cache($cacheForImage$(image));
500 [Cache_ setObject:cache forKey:key];
505 _SBIconModel$cacheImageForIcon$(self, sel, icon);
508 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
509 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
510 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
512 NSString *key([icon displayIdentifier]);
514 if (UIImage *image = [icon icon]) {
515 CGSize size = [image size];
516 if (size.width != 59 || size.height != 60) {
517 UIImage *cache($cacheForImage$(image));
518 [Cache_ setObject:cache forKey:key];
524 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
525 NSString *key([icon displayIdentifier]);
526 if (UIImage *image = [Cache_ objectForKey:key])
529 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
532 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
534 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
535 NSString *key([icon displayIdentifier]);
536 if (UIImage *image = [Cache_ objectForKey:key])
539 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
542 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
543 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
544 [self setBackgroundColor:[UIColor clearColor]];
545 for (UIView *child in [self subviews])
546 [child setBackgroundColor:[UIColor clearColor]];
550 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
551 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
552 [self setBackgroundColor:[UIColor clearColor]];
556 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
557 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
558 float inset([self edgeInset]);
559 [[UIColor clearColor] set];
560 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
561 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
564 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
565 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
566 if (NSString *path = $pathForIcon$([self application]))
567 return [UIImage imageWithContentsOfFile:path];
568 return _SBApplicationIcon$icon(self, sel);
571 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
573 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
574 if (IsWild_ && false) // XXX: delete this code, it should not be supported
575 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
576 return [UIImage imageWithContentsOfFile:path72];
577 if (NSString *path = $pathForIcon$([self application]))
578 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
580 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
581 width = [$SBIcon defaultIconImageSize].width;
584 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
587 return _SBApplicationIcon$generateIconImage$(self, sel, type);
590 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
592 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
593 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
594 return [UIImage imageWithContentsOfFile:path];
595 return _SBWidgetApplicationIcon$icon(self, sel);
598 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
600 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
601 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
602 return [UIImage imageWithContentsOfFile:path];
603 return _SBBookmarkIcon$icon(self, sel);
606 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
607 if (NSString *path = $pathForIcon$(self))
609 return _SBApplication$pathForIcon(self, sel);
612 static UIImage *CachedImageAtPath(NSString *path) {
613 path = [path stringByResolvingSymlinksInPath];
614 UIImage *image = [PathImages_ objectForKey:path];
616 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
617 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
619 image = [image autorelease];
620 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
624 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
625 NSBundle *bundle = [NSBundle mainBundle];
627 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
628 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
629 return CachedImageAtPath(path);
630 return __UIApplicationImageWithName(name);
633 #define WBDelegate(delegate) \
634 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
636 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
637 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
639 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
643 - (void) forwardInvocation:(NSInvocation*)inv { \
644 SEL sel = [inv selector]; \
645 if ([delegate respondsToSelector:sel]) \
646 [inv invokeWithTarget:delegate]; \
648 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
651 // %hook -[NSBundle pathForResource:ofType:] {{{
652 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
653 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
655 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
656 if (NSString *path = $pathForFile$inBundle$(file, self, false))
658 return MSOldCall(resource, type);
662 static struct WBStringDrawingState {
663 WBStringDrawingState *next_;
667 } *stringDrawingState_;
669 MSInstanceMessageHook4(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode, CGPoint, point, float, width, UIFont *, font, int, mode) {
670 WBStringDrawingState *state(stringDrawingState_);
672 return MSOldCall(point, width, font, mode);
674 if (--state->count_ == 0)
675 stringDrawingState_ = state->next_;
676 if (state->info_ == nil)
677 return MSOldCall(point, width, font, mode);
679 NSString *info([Info_ objectForKey:state->info_]);
681 return MSOldCall(point, width, font, mode);
683 NSString *base(state->base_ ?: @"");
684 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]];
688 MSInstanceMessageHook2(CGSize, NSString, drawAtPoint,withFont, CGPoint, point, UIFont *, font) {
689 WBStringDrawingState *state(stringDrawingState_);
691 return MSOldCall(point, font);
693 if (--state->count_ == 0)
694 stringDrawingState_ = state->next_;
695 if (state->info_ == nil)
696 return MSOldCall(point, font);
698 NSString *info([Info_ objectForKey:state->info_]);
700 return MSOldCall(point, font);
702 NSString *base(state->base_ ?: @"");
703 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]];
707 MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) {
708 WBStringDrawingState *state(stringDrawingState_);
710 return MSOldCall(font);
712 if (--state->count_ == 0)
713 stringDrawingState_ = state->next_;
714 if (state->info_ == nil)
715 return MSOldCall(font);
717 NSString *info([Info_ objectForKey:state->info_]);
719 return MSOldCall(font);
721 NSString *base(state->base_ ?: @"");
722 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info] forWidth:65535];
725 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
726 WBStringDrawingState badgeState = {NULL, 1, @""
730 stringDrawingState_ = &badgeState;
732 UIImage *image(MSOldCall(text));
734 stringDrawingState_ = NULL;
738 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
739 WBStringDrawingState dayState = {NULL, 2, @""
741 // XXX: this is only correct on an iPod dock
742 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
743 , @"CalendarIconDayStyle"};
745 WBStringDrawingState sizeState = {&dayState, 7, nil, nil};
747 WBStringDrawingState dateState = {&sizeState, 2, @""
749 , @"CalendarIconDateStyle"};
751 stringDrawingState_ = &dateState;
753 UIImage *image(MSOldCall(type));
755 stringDrawingState_ = NULL;
759 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
760 NSBundle *bundle([NSBundle mainBundle]);
762 CFLocaleRef locale(CFLocaleCopyCurrent());
763 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
766 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
768 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
769 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
770 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
771 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
775 CFRelease(formatter);
777 NSString *datestyle([@""
778 "font-family: Helvetica; "
779 "font-weight: bold; "
782 "" stringByAppendingString:(IsWild_
783 ? @"font-size: 54px; "
784 : @"font-size: 39px; "
787 NSString *daystyle([@""
788 "font-family: Helvetica; "
789 "font-weight: bold; "
791 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
792 "" stringByAppendingString:(IsWild_
793 ? @"font-size: 11px; "
794 : @"font-size: 9px; "
797 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
798 datestyle = [datestyle stringByAppendingString:style];
799 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
800 daystyle = [daystyle stringByAppendingString:style];
802 float width([self bounds].size.width);
804 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
805 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
807 unsigned base0(IsWild_ ? 89 : 70);
808 if ($GSFontGetUseLegacyFontMetrics())
810 unsigned base1(IsWild_ ? 18 : 16);
817 [(NSString *)date drawAtPoint:CGPointMake(
818 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
819 ) withStyle:datestyle];
821 [(NSString *)day drawAtPoint:CGPointMake(
822 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
823 ) withStyle:daystyle];
829 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
830 void $setBarStyle$_(NSString *name, int &style) {
832 NSLog(@"WB:Debug:%@Style:%d", name, style);
833 NSNumber *number = nil;
835 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
837 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
839 style = [number intValue];
841 NSLog(@"WB:Debug:%@Style=%d", name, style);
845 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
846 $setBarStyle$_(@"Toolbar", style);
847 return MSOldCall(style);
850 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
851 $setBarStyle$_(@"NavigationBar", style);
852 return MSOldCall(style);
856 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
857 [[self superview] setBackgroundColor:[UIColor clearColor]];
858 _SBButtonBar$didMoveToSuperview(self, sel);
861 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
862 [[self superview] setBackgroundColor:[UIColor clearColor]];
863 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
866 static NSArray *Wallpapers_;
867 static bool Papered_;
869 static NSString *WallpaperFile_;
870 static UIImageView *WallpaperImage_;
871 static UIWebDocumentView *WallpaperPage_;
872 static NSURL *WallpaperURL_;
874 #define _release(object) \
875 do if (object != nil) { \
880 static UIImage *$getImage$(NSString *path) {
881 UIImage *image([UIImage imageWithContentsOfFile:path]);
883 unsigned scale($getScale$(path));
884 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
885 [image setScale:scale];
890 static UIImage *$getDefaultDesktopImage$() {
891 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
892 return $getImage$(path);
896 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
897 return $getDefaultDesktopImage$() ?: MSOldCall();
900 MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
901 return $getDefaultDesktopImage$() ?: MSOldCall();
904 MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
905 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
906 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
907 if (UIImage *image = $getDefaultDesktopImage$()) {
908 [self setImage:image];
918 // %hook -[SBUIController init] {{{
919 MSInstanceMessageHook0(id, SBUIController, init) {
924 NSString *paper($getTheme$(Wallpapers_));
926 paper = [paper stringByDeletingLastPathComponent];
930 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
931 char *machine = new char[size];
933 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
934 perror("sysctlbyname(\"hw.machine\", ?)");
939 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
943 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
946 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
947 if (&_wallpaperView != NULL) {
948 [_wallpaperView removeFromSuperview];
949 [_wallpaperView release];
950 _wallpaperView = nil;
954 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
955 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
958 if (&_contentLayer != NULL)
959 player = &_contentLayer;
960 else if (&_contentView != NULL)
961 player = &_contentView;
964 UIView *layer(player == NULL ? nil : *player);
966 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
967 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
968 [window setContentView:content];
970 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
971 [window setBackgroundColor:[_window backgroundColor]];
972 [_window setBackgroundColor:[UIColor clearColor]];
974 [window setLevel:-1000];
975 [window setHidden:NO];
977 /*if (player != NULL)
980 [content setBackgroundColor:[layer backgroundColor]];
981 [layer setBackgroundColor:[UIColor clearColor]];
984 if (!SummerBoard_ || !IsWild_)
987 CGRect bounds([content bounds]);
988 bounds.origin.y = -30;
989 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
990 [content addSubview:indirect];
991 [indirect zoomToScale:2.4];
994 _release(WallpaperFile_);
995 _release(WallpaperImage_);
996 _release(WallpaperPage_);
997 _release(WallpaperURL_);
1000 NSArray *themes([NSArray arrayWithObject:paper]);
1002 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1006 static AVController *controller_(nil);
1007 if (controller_ == nil) {
1008 AVQueue *queue([AVQueue avQueue]);
1009 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1012 AVQueue *queue([controller_ queue]);
1014 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1015 [controller_ setLayer:[video _layer]];
1017 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1018 [queue appendItem:item error:&error];
1020 [controller_ play:&error];
1021 #elif UseMPMoviePlayerController
1022 NSURL *url([NSURL fileURLWithPath:path]);
1023 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1024 controller.movieControlMode = MPMovieControlModeHidden;
1027 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1028 [video setMovieWithPath:path];
1029 [video setRepeatMode:1];
1030 [video setRepeatGap:-1];
1031 [video playFromBeginning];;
1034 [indirect addSubview:video];
1037 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1038 if (UIImage *image = $getImage$(path)) {
1039 WallpaperFile_ = [path retain];
1040 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1041 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1042 [WallpaperImage_ setAlpha:[number floatValue]];
1043 [indirect addSubview:WallpaperImage_];
1047 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1048 CGRect bounds = [indirect bounds];
1050 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1051 [view setAutoresizes:true];
1053 WallpaperPage_ = [view retain];
1054 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1056 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1058 [view setBackgroundColor:[UIColor clearColor]];
1059 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1060 [view setDrawsBackground:NO];
1061 [[view webView] setDrawsBackground:NO];
1063 [indirect addSubview:view];
1067 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1068 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1069 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1070 if ([Manager_ fileExistsAtPath:html]) {
1071 CGRect bounds = [indirect bounds];
1073 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1074 [view setAutoresizes:true];
1076 NSURL *url = [NSURL fileURLWithPath:html];
1077 [view loadRequest:[NSURLRequest requestWithURL:url]];
1079 [view setBackgroundColor:[UIColor clearColor]];
1080 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1081 [view setDrawsBackground:NO];
1082 [[view webView] setDrawsBackground:NO];
1084 [indirect addSubview:view];
1092 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1093 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1094 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1096 if (path != nil && _backgroundView != nil)
1099 _SBAwayView$updateDesktopImage$(self, sel, image);
1102 CGRect bounds = [self bounds];
1104 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1105 [view setAutoresizes:true];
1107 if (WallpaperPage_ != nil)
1108 [WallpaperPage_ release];
1109 WallpaperPage_ = [view retain];
1111 if (WallpaperURL_ != nil)
1112 [WallpaperURL_ release];
1113 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1115 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1117 [[view webView] setDrawsBackground:false];
1118 [view setBackgroundColor:[UIColor clearColor]];
1120 [self insertSubview:view aboveSubview:_backgroundView];
1124 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1125 extern "C" CGColorRef CGGStateGetFillColor(void *);
1126 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1127 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1129 /* WBTimeLabel {{{ */
1130 @interface WBTimeLabel : NSProxy {
1132 _transient SBStatusBarTimeView *view_;
1135 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1139 @implementation WBTimeLabel
1146 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1147 time_ = [time retain];
1152 - (NSString *) description {
1158 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1159 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1160 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1162 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1163 "font-family: Helvetica; "
1164 "font-weight: bold; "
1167 "%@", _mode ? @"white" : @"black", custom]];
1172 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1177 /* WBBadgeLabel {{{ */
1178 @interface WBBadgeLabel : NSProxy {
1182 - (id) initWithBadge:(NSString *)badge;
1183 - (NSString *) description;
1187 @implementation WBBadgeLabel
1194 - (id) initWithBadge:(NSString *)badge {
1195 badge_ = [badge retain];
1199 - (NSString *) description {
1200 return [badge_ description];
1205 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1206 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1207 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1208 "font-family: Helvetica; "
1209 "font-weight: bold; "
1217 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1224 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1225 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1226 alpha = [number floatValue];
1227 return MSOldCall(alpha);
1230 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1231 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1232 alpha = [number floatValue];
1233 return MSOldCall(alpha);
1236 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1237 if ((self = MSOldCall()) != nil) {
1238 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1239 // XXX: note: this is overridden above, which is silly
1240 float alpha([number floatValue]);
1241 [self setIconImageAlpha:alpha];
1242 [self setIconLabelAlpha:alpha];
1247 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1248 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1249 alpha = [number floatValue];
1250 return MSOldCall(alpha);
1254 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1255 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1256 id &_badge(MSHookIvar<id>(self, "_badge"));
1258 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1263 void SBStatusBarController$setStatusBarMode(int &mode) {
1265 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1266 if (mode < 100) // 104:hidden 105:glowing
1267 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1268 mode = [number intValue];
1271 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1272 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1273 SBStatusBarController$setStatusBarMode(mode);
1274 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1277 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1278 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1279 SBStatusBarController$setStatusBarMode(mode);
1280 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1283 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) {
1284 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1285 SBStatusBarController$setStatusBarMode(mode);
1286 //NSLog(@"mode=%u", mode);
1287 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1290 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1291 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1292 mode = [number intValue];
1293 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1296 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1297 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1299 NSLog(@"operatorNameStyle= %@", style);
1300 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1301 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1305 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1307 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1308 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1311 // XXX: replace this with [SBStatusBarTimeView tile]
1312 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1313 id &_time(MSHookIvar<id>(self, "_time"));
1314 if (_time != nil && [_time class] != [WBTimeLabel class])
1315 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1316 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1319 @interface UIView (WinterBoard)
1320 - (bool) wb$isWBImageView;
1321 - (void) wb$logHierarchy;
1322 - (void) wb$setBackgroundColor:(UIColor *)color;
1325 @implementation UIView (WinterBoard)
1327 - (bool) wb$isWBImageView {
1331 - (void) wb$logHierarchy {
1332 WBLogHierarchy(self);
1335 - (void) wb$setBackgroundColor:(UIColor *)color {
1336 [self setBackgroundColor:color];
1337 for (UIView *child in [self subviews])
1338 [child wb$setBackgroundColor:color];
1343 @interface WBImageView : UIImageView {
1346 - (bool) wb$isWBImageView;
1347 - (void) wb$updateFrame;
1350 @implementation WBImageView
1352 - (bool) wb$isWBImageView {
1356 - (void) wb$updateFrame {
1357 CGRect frame([self frame]);
1360 for (UIView *view(self); ; ) {
1361 view = [view superview];
1364 frame.origin.y -= [view frame].origin.y;
1367 [self setFrame:frame];
1372 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1373 NSArray *subviews([self subviews]);
1374 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1375 if (view != nil && [view wb$isWBImageView])
1376 [view wb$updateFrame];
1377 _SBIconList$setFrame$(self, sel, frame);
1380 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1381 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1382 NSArray *lists([_iconModel iconLists]);
1384 for (unsigned i(0), e([lists count]); i != e; ++i)
1385 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]])) {
1386 SBIconList *list([lists objectAtIndex:i]);
1387 NSArray *subviews([list subviews]);
1389 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1390 if (view == nil || ![view wb$isWBImageView]) {
1391 view = [[[WBImageView alloc] init] autorelease];
1392 [list insertSubview:view atIndex:0];
1395 UIImage *image([UIImage imageWithContentsOfFile:path]);
1397 CGRect frame([view frame]);
1398 frame.size = [image size];
1399 [view setFrame:frame];
1401 [view setImage:image];
1402 [view wb$updateFrame];
1405 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1408 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1409 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1411 [self setClipsToBounds:NO];
1415 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1416 static bool gssc(false);
1418 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1419 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1422 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1423 [Info_ setObject:[NSNumber numberWithBool:(
1425 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1426 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1427 )] forKey:@"UndockedIconLabels"];
1430 id &_label(MSHookIvar<id>(self, "_label"));
1431 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1434 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1435 [_label setInDock:docked];
1437 _SBIconLabel$setInDock$(self, sel, docked);
1438 [self setNeedsDisplay];
1441 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1442 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1445 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1446 _SBDockIconListView$setFrame$(self, sel, frame);
1449 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1450 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1451 NSString *identifier = [self bundleIdentifier];
1452 NSLocale *locale = [NSLocale currentLocale];
1453 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1455 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1456 NSString *file = table == nil ? @"Localizable" : table;
1457 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1458 NSDictionary *strings;
1459 if ((strings = [Strings_ objectForKey:name]) != nil) {
1460 if (static_cast<id>(strings) != [NSNull null]) strings:
1461 if (NSString *value = [strings objectForKey:key])
1463 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1466 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1467 [Strings_ setObject:[strings autorelease] forKey:name];
1471 [Strings_ setObject:[NSNull null] forKey:name];
1472 return MSOldCall(key, value, table);
1475 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1476 MSClassHook(WebCoreFrameBridge)
1478 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1481 void **core(reinterpret_cast<void **>([node _node]));
1482 if (core == NULL || core[6] == NULL)
1484 return MSOldCall(node, width);
1488 MSInstanceMessageHook1(void, SBIconLabel, drawRect, CGRect, rect) {
1489 CGRect bounds = [self bounds];
1491 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1494 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1495 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1497 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1499 NSString *style = [NSString stringWithFormat:@""
1500 "font-family: Helvetica; "
1501 "font-weight: bold; "
1503 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1504 ? @"font-size: 12px; "
1505 : @"font-size: 11px; "
1509 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1511 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1513 bool ellipsis(false);
1514 float max = [self frame].size.width - 11, width;
1516 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
1519 size_t length([label length]);
1520 float spacing((width - max) / (length - 1));
1522 if (spacing > 1.25) {
1524 label = [label substringToIndex:(length - 1)];
1528 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
1532 label = [label stringByAppendingString:@"..."];
1534 if (NSString *custom = [Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")])
1535 style = [style stringByAppendingString:custom];
1537 CGSize size = [label sizeWithStyle:style forWidth:bounds.size.width];
1538 [label drawAtPoint:CGPointMake((bounds.size.width - size.width) / 2, 0) withStyle:style];
1542 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1544 [balloon setBackgroundColor:[UIColor clearColor]];
1547 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1548 MSOldCall([UIColor clearColor]);
1549 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1552 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1553 if ((self = MSOldCall(style, reuse)) != nil) {
1554 [self setBackgroundColor:[UIColor clearColor]];
1555 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1559 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1560 if ((self = MSOldCall(style, reuse)) != nil) {
1561 [self setBackgroundColor:[UIColor clearColor]];
1562 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1566 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1567 if ((self = MSOldCall(style, reuse)) != nil) {
1568 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1569 [_label setBackgroundColor:[UIColor clearColor]];
1573 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1574 MSOldCall(UITableViewCellSeparatorStyleNone);
1577 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1578 if ((self = MSOldCall(frame, style)) != nil) {
1579 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1583 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1586 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1587 if (UIImage *image = $getImage$(path)) {
1588 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1589 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1591 if (&_transcriptTable != NULL)
1592 table = _transcriptTable;
1593 else if (&_transcriptLayer != NULL)
1594 table = _transcriptLayer;
1598 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1599 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1602 [placard insertSubview:background atIndex:0];
1604 [table setBackgroundColor:[UIColor clearColor]];
1605 [placard insertSubview:background belowSubview:table];
1611 // %hook _UIImageWithName() {{{
1612 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1614 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1621 if (_UIPackedImageTableGetIdentifierForName != NULL)
1622 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1623 else if (_UISharedImageNameGetIdentifier != NULL) {
1624 identifier = _UISharedImageNameGetIdentifier(name);
1625 packed = identifier != -1;
1632 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1635 return __UIImageWithName(name);
1637 NSNumber *key([NSNumber numberWithInt:identifier]);
1638 UIImage *image([UIImages_ objectForKey:key]);
1640 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1641 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1642 image = $getImage$(path);
1643 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1647 image = __UIImageWithName(name);
1650 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1651 if (![Manager_ fileExistsAtPath:path])
1652 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1659 // %hook _UIImageWithNameInDomain() {{{
1660 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1661 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1662 UIImage *image([PathImages_ objectForKey:key]);
1664 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1666 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1667 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1668 image = $getImage$(path);
1669 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1670 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1674 // %hook GSFontCreateWithName() {{{
1675 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1677 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1678 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1679 name = [font UTF8String];
1680 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1681 // size *= [scale floatValue];
1682 return _GSFontCreateWithName(name, traits, size);
1686 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1687 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1689 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1691 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1693 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1694 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1696 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1699 NSString *path = [NSString stringWithUTF8String:a1];
1700 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1701 NSString *file = [path substringFromIndex:31];
1702 for (NSString *theme in Themes_) {
1703 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1704 if ([Manager_ fileExistsAtPath:path]) {
1705 strcpy(a1, [path UTF8String]);
1714 static void ChangeWallpaper(
1715 CFNotificationCenterRef center,
1719 CFDictionaryRef info
1722 NSLog(@"WB:Debug:ChangeWallpaper!");
1725 if (WallpaperFile_ != nil) {
1726 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1728 image = [image autorelease];
1731 if (WallpaperImage_ != nil)
1732 [WallpaperImage_ setImage:image];
1733 if (WallpaperPage_ != nil)
1734 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1738 #define WBRename(name, sel, imp) \
1739 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
1741 template <typename Type_>
1742 static void msset(Type_ &function, MSImageRef image, const char *name) {
1743 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1746 template <typename Type_>
1747 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1748 struct nlist &name(nl[index]);
1749 uintptr_t value(name.n_value);
1750 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1751 value |= 0x00000001;
1752 function = reinterpret_cast<Type_>(value);
1755 template <typename Type_>
1756 static void dlset(Type_ &function, const char *name) {
1757 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1760 // %hook CGImageReadCreateWithFile() {{{
1761 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1763 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1764 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1765 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1771 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
1772 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1773 if (style == nil || [style length] == 0)
1774 style = @"font-family: Helvetica; font-size: 12px";
1775 return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
1778 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
1779 if (style == nil || [style length] == 0)
1780 style = @"font-family: Helvetica; font-size: 12px";
1781 return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width];
1784 static void SBInitialize() {
1785 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
1786 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
1789 WBRename(SBApplication, pathForIcon, pathForIcon);
1790 WBRename(SBApplicationIcon, icon, icon);
1791 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1794 WBRename(SBBookmarkIcon, icon, icon);
1795 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1796 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1797 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1798 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
1800 WBRename(SBWidgetApplicationIcon, icon, icon);
1802 WBRename(SBDockIconListView, setFrame:, setFrame$);
1803 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
1805 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
1806 WBRename(SBIconLabel, setInDock:, setInDock$);
1808 WBRename(SBIconList, setFrame:, setFrame$);
1810 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
1811 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
1812 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
1813 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
1815 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
1816 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
1817 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
1819 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
1821 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
1822 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
1823 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
1824 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
1825 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
1826 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
1827 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
1828 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
1829 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
1832 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
1836 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1838 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
1839 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
1841 Manager_ = [[NSFileManager defaultManager] retain];
1842 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
1844 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
1846 // Load Settings.plist {{{
1847 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
1848 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
1849 SummerBoard_ = [value boolValue];
1850 if (NSNumber *value = [settings objectForKey:@"Debug"])
1851 Debug_ = [value boolValue];
1852 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
1853 UIDebug_ = [value boolValue];
1855 NSArray *themes([settings objectForKey:@"Themes"]);
1857 if (NSString *theme = [settings objectForKey:@"Theme"])
1858 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
1860 [NSNumber numberWithBool:true], @"Active",
1864 for (NSDictionary *theme in themes) {
1865 NSNumber *active([theme objectForKey:@"Active"]);
1866 if (![active boolValue])
1869 NSString *name([theme objectForKey:@"Name"]);
1873 NSString *theme(nil);
1875 #define testForTheme(format...) \
1876 if (theme == nil) { \
1877 NSString *path = [NSString stringWithFormat:format]; \
1878 if ([Manager_ fileExistsAtPath:path]) { \
1879 [Themes_ addObject:path]; \
1884 testForTheme(@"/Library/Themes/%@.theme", name)
1885 testForTheme(@"/Library/Themes/%@", name)
1886 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
1891 // Merge Info.plist {{{
1892 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1894 for (NSString *theme in Themes_)
1895 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
1896 for (NSString *key in [info allKeys])
1897 if ([Info_ objectForKey:key] == nil)
1898 [Info_ setObject:[info objectForKey:key] forKey:key];
1902 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
1903 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
1904 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
1907 // GraphicsServices {{{
1909 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
1913 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
1914 void *(*CGImageReadCreateWithFile)(NSString *, int);
1915 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
1916 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
1921 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
1922 Papered_ = $getTheme$(Wallpapers_) != nil;
1923 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]);
1925 CFNotificationCenterAddObserver(
1926 CFNotificationCenterGetDarwinNotifyCenter(),
1927 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
1930 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
1931 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
1932 if (MediaPlayer != nil)
1935 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
1936 $MPVideoView = objc_getClass("MPVideoView");
1943 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
1945 memset(nl, 0, sizeof(nl));
1946 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
1947 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
1948 nl[2].n_un.n_name = (char *) "__UIKitBundle";
1949 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
1950 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
1953 nlset(_UIApplicationImageWithName, nl, 0);
1954 nlset(_UIImageWithNameInDomain, nl, 1);
1955 nlset(_UIKitBundle, nl, 2);
1956 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
1957 nlset(_UISharedImageNameGetIdentifier, nl, 4);
1959 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
1960 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
1961 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
1965 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
1966 NSError *error(nil);
1967 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
1968 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
1970 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);