]> git.saurik.com Git - winterboard.git/blob - Library.mm
Add a != nil that was forgotten.
[winterboard.git] / Library.mm
1 /* WinterBoard - Theme Manager for the iPhone
2 * Copyright (C) 2008-2011 Jay Freeman (saurik)
3 */
4
5 /*
6 * Redistribution and use in source and binary
7 * forms, with or without modification, are permitted
8 * provided that the following conditions are met:
9 *
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
17 * distribution.
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.
21 *
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.
36 */
37
38 #include <sys/time.h>
39
40 struct timeval _ltv;
41 bool _itv;
42
43 #define _trace() do { \
44 struct timeval _ctv; \
45 gettimeofday(&_ctv, NULL); \
46 if (!_itv) { \
47 _itv = true; \
48 _ltv = _ctv; \
49 } \
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__\
54 ); \
55 _ltv = _ctv; \
56 } while (false)
57
58 #define _transient
59
60 #import <CoreFoundation/CoreFoundation.h>
61 #import <Foundation/Foundation.h>
62 #import <CoreGraphics/CoreGraphics.h>
63 #import <ImageIO/CGImageSource.h>
64
65 #import <Celestial/AVController.h>
66 #import <Celestial/AVItem.h>
67 #import <Celestial/AVQueue.h>
68
69 #include <substrate.h>
70
71 #import <UIKit/UIKit.h>
72
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>
93
94 #import <MobileSMS/mSMSMessageTranscriptController.h>
95
96 #import <MediaPlayer/MPMoviePlayerController.h>
97 #import <MediaPlayer/MPVideoView.h>
98 #import <MediaPlayer/MPVideoView-PlaybackControl.h>
99
100 #import <CoreGraphics/CGGeometry.h>
101
102 #import <ChatKit/CKMessageCell.h>
103
104 #include <sys/sysctl.h>
105
106 #include "WBMarkup.h"
107
108 extern "C" void __clear_cache (char *beg, char *end);
109
110 @protocol WinterBoard
111 - (void *) _node;
112 @end
113
114 Class $MPMoviePlayerController;
115 Class $MPVideoView;
116
117 MSClassHook(NSBundle)
118 MSClassHook(NSString)
119
120 MSClassHook(UIImage)
121 MSMetaClassHook(UIImage)
122 MSClassHook(UINavigationBar)
123 MSClassHook(UIToolbar)
124
125 MSClassHook(CKBalloonView)
126 MSClassHook(CKMessageCell)
127 MSClassHook(CKTimestampView)
128 MSClassHook(CKTranscriptCell)
129 MSClassHook(CKTranscriptController)
130 MSClassHook(CKTranscriptHeaderView)
131 MSClassHook(CKTranscriptTableView)
132
133 MSClassHook(SBApplication)
134 MSClassHook(SBApplicationIcon)
135 MSClassHook(SBAwayView)
136 MSClassHook(SBBookmarkIcon)
137 MSClassHook(SBButtonBar)
138 MSClassHook(SBCalendarApplicationIcon)
139 MSClassHook(SBCalendarIconContentsView)
140 MSClassHook(SBDockIconListView)
141 MSClassHook(SBIcon)
142 MSClassHook(SBIconBadge)
143 MSClassHook(SBIconBadgeFactory)
144 MSClassHook(SBIconController)
145 MSClassHook(SBIconLabel)
146 MSClassHook(SBIconList)
147 MSClassHook(SBIconModel)
148 //MSClassHook(SBImageCache)
149 MSClassHook(SBSearchView)
150 MSClassHook(SBSearchTableViewCell)
151 MSClassHook(SBSlidingAlertDisplay)
152 MSClassHook(SBStatusBarContentsView)
153 MSClassHook(SBStatusBarController)
154 MSClassHook(SBStatusBarOperatorNameView)
155 MSClassHook(SBStatusBarTimeView)
156 MSClassHook(SBUIController)
157 MSClassHook(SBWallpaperView)
158 MSClassHook(SBWidgetApplicationIcon)
159
160 extern "C" void WKSetCurrentGraphicsContext(CGContextRef);
161
162 __attribute__((__constructor__))
163 static void MSFixClass() {
164 if ($SBIcon == nil)
165 $SBIcon = objc_getClass("SBIconView");
166 if ($CKTranscriptController == nil)
167 $CKTranscriptController = objc_getClass("mSMSMessageTranscriptController");
168 }
169
170 static bool IsWild_;
171 static bool Four_($SBDockIconListView != nil);
172
173 @interface NSDictionary (WinterBoard)
174 - (UIColor *) wb$colorForKey:(NSString *)key;
175 - (BOOL) wb$boolForKey:(NSString *)key;
176 @end
177
178 @implementation NSDictionary (WinterBoard)
179
180 - (UIColor *) wb$colorForKey:(NSString *)key {
181 NSString *value = [self objectForKey:key];
182 if (value == nil)
183 return nil;
184 /* XXX: incorrect */
185 return nil;
186 }
187
188 - (BOOL) wb$boolForKey:(NSString *)key {
189 if (NSString *value = [self objectForKey:key])
190 return [value boolValue];
191 return false;
192 }
193
194 @end
195
196 static BOOL (*_GSFontGetUseLegacyFontMetrics)();
197 #define $GSFontGetUseLegacyFontMetrics() \
198 (_GSFontGetUseLegacyFontMetrics == NULL ? YES : _GSFontGetUseLegacyFontMetrics())
199
200 static bool Debug_ = false;
201 static bool UIDebug_ = false;
202 static bool Engineer_ = false;
203 static bool SummerBoard_ = true;
204 static bool SpringBoard_;
205
206 static UIImage *(*_UIApplicationImageWithName)(NSString *name);
207 static UIImage *(*_UIImageWithNameInDomain)(NSString *name, NSString *domain);
208 static NSBundle *(*_UIKitBundle)();
209 static bool (*_UIPackedImageTableGetIdentifierForName)(NSString *, int *);
210 static int (*_UISharedImageNameGetIdentifier)(NSString *);
211
212 static NSMutableDictionary *UIImages_ = [[NSMutableDictionary alloc] initWithCapacity:32];
213 static NSMutableDictionary *PathImages_ = [[NSMutableDictionary alloc] initWithCapacity:16];
214 static NSMutableDictionary *Cache_ = [[NSMutableDictionary alloc] initWithCapacity:64];
215 static NSMutableDictionary *Strings_ = [[NSMutableDictionary alloc] initWithCapacity:0];
216 static NSMutableDictionary *Bundles_ = [[NSMutableDictionary alloc] initWithCapacity:2];
217
218 static NSFileManager *Manager_;
219 static NSMutableArray *Themes_;
220
221 static NSDictionary *English_;
222 static NSMutableDictionary *Info_;
223
224 // $getTheme$() {{{
225 static NSMutableDictionary *Themed_ = [[NSMutableDictionary alloc] initWithCapacity:128];
226
227 static unsigned Scale_ = 0;
228
229 static unsigned $getScale$(NSString *path) {
230 NSString *name(path);
231
232 #define StripName(strip) \
233 if ([name hasSuffix:@ strip]) \
234 name = [name substringWithRange:NSMakeRange(0, [name length] - sizeof(strip) - 1)];
235
236 StripName(".png");
237 StripName(".jpg");
238 StripName("~iphone");
239 StripName("~ipad");
240
241 return [name hasSuffix:@"@2x"] ? 2 : 1;
242 }
243
244 static NSArray *$useScale$(NSArray *files, bool use = true) {
245 if (Scale_ == 0) {
246 UIScreen *screen([UIScreen mainScreen]);
247 if ([screen respondsToSelector:@selector(scale)])
248 Scale_ = [screen scale];
249 else
250 Scale_ = 1;
251 }
252
253 if (Scale_ == 1)
254 return files;
255
256 NSString *idiom(IsWild_ ? @"ipad" : @"iphone");
257
258 NSMutableArray *scaled([NSMutableArray arrayWithCapacity:([files count] * 4)]);
259
260 for (NSString *file in files) {
261 NSString *base([file stringByDeletingPathExtension]);
262 NSString *extension([file pathExtension]);
263
264 if (use) {
265 if (Scale_ == 2) {
266 [scaled addObject:[NSString stringWithFormat:@"%@@2x~%@.%@", base, idiom, extension]];
267 if (!IsWild_)
268 [scaled addObject:[NSString stringWithFormat:@"%@@2x.%@", base, extension]];
269 }
270
271 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
272
273 // if (!IsWild_) <- support old themes
274 [scaled addObject:file];
275 } else if ([base hasSuffix: @"@2x"]) {
276 [scaled addObject:[NSString stringWithFormat:@"%@~iphone.%@", base, extension]];
277 [scaled addObject:file];
278
279 NSString *rest([base substringWithRange:NSMakeRange(0, [base length] - 3)]);
280 [scaled addObject:[NSString stringWithFormat:@"%@~iphone.%@", rest, extension]];
281 [scaled addObject:[rest stringByAppendingPathExtension:extension]];
282 } else {
283 // XXX: this code isn't really complete
284
285 [scaled addObject:file];
286
287 if ([base hasSuffix:@"~iphone"])
288 [scaled addObject:[[base substringWithRange:NSMakeRange(0, [base length] - 7)] stringByAppendingPathExtension:extension]];
289 }
290 }
291
292 return scaled;
293 }
294
295 static NSString *$getTheme$(NSArray *files, NSArray *themes = Themes_) {
296 if (NSString *path = [Themed_ objectForKey:files])
297 return reinterpret_cast<id>(path) == [NSNull null] ? nil : path;
298
299 if (Debug_)
300 NSLog(@"WB:Debug: %@", [files description]);
301
302 NSString *path;
303
304 for (NSString *theme in Themes_)
305 for (NSString *file in files) {
306 path = [NSString stringWithFormat:@"%@/%@", theme, file];
307 if ([Manager_ fileExistsAtPath:path])
308 goto set;
309 }
310
311 path = nil;
312 set:
313
314 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:files];
315 return path;
316 }
317 // }}}
318 // $pathForFile$inBundle$() {{{
319 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool ui) {
320 NSString *identifier = [bundle bundleIdentifier];
321 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
322
323 if (identifier != nil)
324 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
325 if (NSString *folder = [[bundle bundlePath] lastPathComponent])
326 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
327 if (ui)
328 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
329
330 #define remapResourceName(oldname, newname) \
331 else if ([file isEqualToString:(oldname)]) \
332 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
333
334 bool summer(SpringBoard_ && SummerBoard_);
335
336 if (identifier == nil);
337 else if ([identifier isEqualToString:@"com.apple.chatkit"])
338 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
339 else if ([identifier isEqualToString:@"com.apple.calculator"])
340 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
341 else if (!summer);
342 remapResourceName(@"FSO_BG.png", @"StatusBar")
343 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
344 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
345
346 if (NSString *path = $getTheme$($useScale$(names, ui)))
347 return path;
348
349 return nil;
350 }
351 // }}}
352
353 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
354 NSString *identifier = [self bundleIdentifier];
355 NSString *path = [self path];
356 NSString *folder = [path lastPathComponent];
357 NSString *dname = [self displayName];
358 NSString *didentifier = [self displayIdentifier];
359
360 if (Debug_)
361 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
362
363 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
364
365 /* XXX: I might need to keep this for backwards compatibility
366 if (identifier != nil)
367 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
368 if (folder != nil)
369 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
370
371 #define testForIcon(Name) \
372 if (NSString *name = Name) \
373 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
374
375 if (![didentifier isEqualToString:identifier])
376 testForIcon(didentifier);
377
378 testForIcon(identifier);
379 testForIcon(dname);
380
381 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
382 testForIcon(@"SMS");
383
384 if (didentifier != nil) {
385 testForIcon([English_ objectForKey:didentifier]);
386
387 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
388 if ([parts count] != 1)
389 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
390 testForIcon([english objectForKey:[parts lastObject]]);
391 }
392
393 if (NSString *path = $getTheme$(names))
394 return path;
395
396 return nil;
397 }
398
399 // -[NSBundle wb$bundleWithFile] {{{
400 @interface NSBundle (WinterBoard)
401 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
402 @end
403
404 @implementation NSBundle (WinterBoard)
405
406 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
407 path = [path stringByDeletingLastPathComponent];
408 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
409 return nil;
410
411 NSBundle *bundle([Bundles_ objectForKey:path]);
412 if (reinterpret_cast<id>(bundle) == [NSNull null])
413 return nil;
414 else if (bundle == nil) {
415 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
416 bundle = [NSBundle bundleWithPath:path];
417 if (bundle == nil)
418 bundle = [NSBundle wb$bundleWithFile:path];
419 if (Debug_)
420 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
421 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
422 }
423
424 return bundle;
425 }
426
427 @end
428 // }}}
429 // -[NSString wb$themedPath] {{{
430 @interface NSString (WinterBoard)
431 - (NSString *) wb$themedPath;
432 @end
433
434 @implementation NSString (WinterBoard)
435
436 - (NSString *) wb$themedPath {
437 if ([self hasPrefix:@"/Library/Themes/"])
438 return self;
439
440 if (Debug_)
441 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
442
443 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
444 NSString *file([self stringByResolvingSymlinksInPath]);
445 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
446 if ([file hasPrefix:prefix]) {
447 NSUInteger length([prefix length]);
448 if (length != [file length])
449 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
450 return path;
451 }
452 }
453
454 return self;
455 }
456
457 @end
458 // }}}
459
460 void WBLogRect(const char *tag, struct CGRect rect) {
461 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
462 }
463
464 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
465 CGRect frame([view frame]);
466 NSLog(@"%*s|%2d:%p:%s : {%f,%f+%f,%f} (%@)", indent * 3, "", index, view, class_getName([view class]), frame.origin.x, frame.origin.y, frame.size.width, frame.size.height, [view backgroundColor]);
467 index = 0;
468 for (UIView *child in [view subviews])
469 WBLogHierarchy(child, index++, indent + 1);
470 }
471
472 UIImage *$cacheForImage$(UIImage *image) {
473 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
474 CGRect rect = {CGPointMake(1, 1), [image size]};
475 CGSize size = {rect.size.width + 2, rect.size.height + 2};
476
477 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
478 CGColorSpaceRelease(space);
479
480 CGContextDrawImage(context, rect, [image CGImage]);
481 CGImageRef ref(CGBitmapContextCreateImage(context));
482 CGContextRelease(context);
483
484 UIImage *cache([UIImage imageWithCGImage:ref]);
485 CGImageRelease(ref);
486
487 return cache;
488 }
489
490 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
491 //if ([name isEqualToString:@"icons"]) return nil;
492 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
493 }*/
494
495 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
496 NSString *key([icon displayIdentifier]);
497
498 if (UIImage *image = [icon icon]) {
499 CGSize size = [image size];
500 if (size.width != 59 || size.height != 60) {
501 UIImage *cache($cacheForImage$(image));
502 [Cache_ setObject:cache forKey:key];
503 return;
504 }
505 }
506
507 _SBIconModel$cacheImageForIcon$(self, sel, icon);
508 }
509
510 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
511 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
512 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
513
514 NSString *key([icon displayIdentifier]);
515
516 if (UIImage *image = [icon icon]) {
517 CGSize size = [image size];
518 if (size.width != 59 || size.height != 60) {
519 UIImage *cache($cacheForImage$(image));
520 [Cache_ setObject:cache forKey:key];
521 return;
522 }
523 }
524 }
525
526 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
527 NSString *key([icon displayIdentifier]);
528 if (UIImage *image = [Cache_ objectForKey:key])
529 return image;
530 else
531 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
532 }
533
534 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
535 if (small)
536 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
537 NSString *key([icon displayIdentifier]);
538 if (UIImage *image = [Cache_ objectForKey:key])
539 return image;
540 else
541 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
542 }
543
544 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
545 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
546 [self setBackgroundColor:[UIColor clearColor]];
547 for (UIView *child in [self subviews])
548 [child setBackgroundColor:[UIColor clearColor]];
549 } return self;
550 }
551
552 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
553 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
554 [self setBackgroundColor:[UIColor clearColor]];
555 } return self;
556 }
557
558 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
559 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
560 float inset([self edgeInset]);
561 [[UIColor clearColor] set];
562 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
563 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
564 }
565
566 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
567 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
568 if (NSString *path = $pathForIcon$([self application]))
569 return [UIImage imageWithContentsOfFile:path];
570 return _SBApplicationIcon$icon(self, sel);
571 }
572
573 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
574 if (type == 2)
575 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
576 if (IsWild_ && false) // XXX: delete this code, it should not be supported
577 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
578 return [UIImage imageWithContentsOfFile:path72];
579 if (NSString *path = $pathForIcon$([self application]))
580 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
581 float width;
582 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
583 width = [$SBIcon defaultIconImageSize].width;
584 else
585 width = 59;
586 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
587 }
588 }
589 return _SBApplicationIcon$generateIconImage$(self, sel, type);
590 }
591
592 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
593 if (Debug_)
594 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
595 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
596 return [UIImage imageWithContentsOfFile:path];
597 return _SBWidgetApplicationIcon$icon(self, sel);
598 }
599
600 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
601 if (Debug_)
602 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
603 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
604 return [UIImage imageWithContentsOfFile:path];
605 return _SBBookmarkIcon$icon(self, sel);
606 }
607
608 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
609 if (NSString *path = $pathForIcon$(self))
610 return path;
611 return _SBApplication$pathForIcon(self, sel);
612 }
613
614 static UIImage *CachedImageAtPath(NSString *path) {
615 path = [path stringByResolvingSymlinksInPath];
616 UIImage *image = [PathImages_ objectForKey:path];
617 if (image != nil)
618 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
619 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
620 if (image != nil)
621 image = [image autorelease];
622 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
623 return image;
624 }
625
626 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
627 NSBundle *bundle = [NSBundle mainBundle];
628 if (Debug_)
629 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
630 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
631 return CachedImageAtPath(path);
632 return __UIApplicationImageWithName(name);
633 }
634
635 #define WBDelegate(delegate) \
636 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
637 if (Engineer_) \
638 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
639 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
640 return sig; \
641 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
642 return nil; \
643 } \
644 \
645 - (void) forwardInvocation:(NSInvocation*)inv { \
646 SEL sel = [inv selector]; \
647 if ([delegate respondsToSelector:sel]) \
648 [inv invokeWithTarget:delegate]; \
649 else \
650 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
651 }
652
653 // %hook -[NSBundle pathForResource:ofType:] {{{
654 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
655 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
656 if (Debug_)
657 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
658 if (NSString *path = $pathForFile$inBundle$(file, self, false))
659 return path;
660 return MSOldCall(resource, type);
661 }
662 // }}}
663
664 static struct WBStringDrawingState {
665 WBStringDrawingState *next_;
666 unsigned count_;
667 NSString *base_;
668 NSString *info_;
669 } *stringDrawingState_;
670
671 MSInstanceMessageHook4(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode, CGPoint, point, float, width, UIFont *, font, int, mode) {
672 WBStringDrawingState *state(stringDrawingState_);
673 if (state == NULL)
674 return MSOldCall(point, width, font, mode);
675
676 if (--state->count_ == 0)
677 stringDrawingState_ = state->next_;
678 if (state->info_ == nil)
679 return MSOldCall(point, width, font, mode);
680
681 NSString *info([Info_ objectForKey:state->info_]);
682 if (info == nil)
683 return MSOldCall(point, width, font, mode);
684
685 NSString *base(state->base_ ?: @"");
686 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]];
687 return CGSizeZero;
688 }
689
690 MSInstanceMessageHook2(CGSize, NSString, drawAtPoint,withFont, CGPoint, point, UIFont *, font) {
691 WBStringDrawingState *state(stringDrawingState_);
692 if (state == NULL)
693 return MSOldCall(point, font);
694
695 if (--state->count_ == 0)
696 stringDrawingState_ = state->next_;
697 if (state->info_ == nil)
698 return MSOldCall(point, font);
699
700 NSString *info([Info_ objectForKey:state->info_]);
701 if (info == nil)
702 return MSOldCall(point, font);
703
704 NSString *base(state->base_ ?: @"");
705 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]];
706 return CGSizeZero;
707 }
708
709 MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) {
710 WBStringDrawingState *state(stringDrawingState_);
711 if (state == NULL)
712 return MSOldCall(font);
713
714 if (--state->count_ == 0)
715 stringDrawingState_ = state->next_;
716 if (state->info_ == nil)
717 return MSOldCall(font);
718
719 NSString *info([Info_ objectForKey:state->info_]);
720 if (info == nil)
721 return MSOldCall(font);
722
723 NSString *base(state->base_ ?: @"");
724 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info] forWidth:65535];
725 }
726
727 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
728 WBStringDrawingState badgeState = {NULL, 1, @""
729 "color: white;"
730 , @"BadgeStyle"};
731
732 stringDrawingState_ = &badgeState;
733
734 UIImage *image(MSOldCall(text));
735
736 stringDrawingState_ = NULL;
737 return image;
738 }
739
740 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
741 WBStringDrawingState dayState = {NULL, 2, @""
742 "color: white;"
743 // XXX: this is only correct on an iPod dock
744 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
745 , @"CalendarIconDayStyle"};
746
747 WBStringDrawingState sizeState = {&dayState, 7, nil, nil};
748
749 WBStringDrawingState dateState = {&sizeState, 2, @""
750 "color: #333333;"
751 , @"CalendarIconDateStyle"};
752
753 stringDrawingState_ = &dateState;
754
755 UIImage *image(MSOldCall(type));
756
757 stringDrawingState_ = NULL;
758 return image;
759 }
760
761 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
762 NSBundle *bundle([NSBundle mainBundle]);
763
764 CFLocaleRef locale(CFLocaleCopyCurrent());
765 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
766 CFRelease(locale);
767
768 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
769
770 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
771 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
772 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
773 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
774
775 CFRelease(now);
776
777 CFRelease(formatter);
778
779 NSString *datestyle([@""
780 "font-family: Helvetica; "
781 "font-weight: bold; "
782 "color: #333333; "
783 "alpha: 1.0; "
784 "" stringByAppendingString:(IsWild_
785 ? @"font-size: 54px; "
786 : @"font-size: 39px; "
787 )]);
788
789 NSString *daystyle([@""
790 "font-family: Helvetica; "
791 "font-weight: bold; "
792 "color: white; "
793 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
794 "" stringByAppendingString:(IsWild_
795 ? @"font-size: 11px; "
796 : @"font-size: 9px; "
797 )]);
798
799 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
800 datestyle = [datestyle stringByAppendingString:style];
801 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
802 daystyle = [daystyle stringByAppendingString:style];
803
804 float width([self bounds].size.width);
805 float leeway(10);
806 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
807 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
808
809 unsigned base0(IsWild_ ? 89 : 70);
810 if ($GSFontGetUseLegacyFontMetrics())
811 base0 = base0 + 1;
812 unsigned base1(IsWild_ ? 18 : 16);
813
814 if (Four_) {
815 ++base0;
816 ++base1;
817 }
818
819 [(NSString *)date drawAtPoint:CGPointMake(
820 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
821 ) withStyle:datestyle];
822
823 [(NSString *)day drawAtPoint:CGPointMake(
824 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
825 ) withStyle:daystyle];
826
827 CFRelease(date);
828 CFRelease(day);
829 }
830
831 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
832 void $setBarStyle$_(NSString *name, int &style) {
833 if (Debug_)
834 NSLog(@"WB:Debug:%@Style:%d", name, style);
835 NSNumber *number = nil;
836 if (number == nil)
837 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
838 if (number == nil)
839 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
840 if (number != nil) {
841 style = [number intValue];
842 if (Debug_)
843 NSLog(@"WB:Debug:%@Style=%d", name, style);
844 }
845 }
846
847 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
848 $setBarStyle$_(@"Toolbar", style);
849 return MSOldCall(style);
850 }
851
852 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
853 $setBarStyle$_(@"NavigationBar", style);
854 return MSOldCall(style);
855 }
856 // }}}
857
858 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
859 [[self superview] setBackgroundColor:[UIColor clearColor]];
860 _SBButtonBar$didMoveToSuperview(self, sel);
861 }
862
863 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
864 [[self superview] setBackgroundColor:[UIColor clearColor]];
865 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
866 }
867
868 static NSArray *Wallpapers_;
869 static bool Papered_;
870 static bool Docked_;
871 static bool SMSBackgrounded_;
872 static NSString *WallpaperFile_;
873 static UIImageView *WallpaperImage_;
874 static UIWebDocumentView *WallpaperPage_;
875 static NSURL *WallpaperURL_;
876
877 #define _release(object) \
878 do if (object != nil) { \
879 [object release]; \
880 object = nil; \
881 } while (false)
882
883 static UIImage *$getImage$(NSString *path) {
884 UIImage *image([UIImage imageWithContentsOfFile:path]);
885
886 unsigned scale($getScale$(path));
887 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
888 [image setScale:scale];
889
890 return image;
891 }
892
893 static UIImage *$getDefaultDesktopImage$() {
894 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
895 return $getImage$(path);
896 return nil;
897 }
898
899 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
900 return $getDefaultDesktopImage$() ?: MSOldCall();
901 }
902
903 MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
904 return $getDefaultDesktopImage$() ?: MSOldCall();
905 }
906
907 MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
908 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
909 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
910 if (UIImage *image = $getDefaultDesktopImage$()) {
911 [self setImage:image];
912 return;
913 }
914
915 break;
916 }
917
918 MSOldCall();
919 }
920
921 // %hook -[SBUIController init] {{{
922 MSInstanceMessageHook0(id, SBUIController, init) {
923 self = MSOldCall();
924 if (self == nil)
925 return nil;
926
927 NSString *paper($getTheme$(Wallpapers_));
928 if (paper != nil)
929 paper = [paper stringByDeletingLastPathComponent];
930
931 {
932 size_t size;
933 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
934 char *machine = new char[size];
935
936 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
937 perror("sysctlbyname(\"hw.machine\", ?)");
938 delete [] machine;
939 machine = NULL;
940 }
941
942 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
943 }
944
945 if (Debug_)
946 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
947
948 if (paper != nil) {
949 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
950 if (&_wallpaperView != NULL) {
951 [_wallpaperView removeFromSuperview];
952 [_wallpaperView release];
953 _wallpaperView = nil;
954 }
955 }
956
957 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
958 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
959
960 UIView **player;
961 if (&_contentLayer != NULL)
962 player = &_contentLayer;
963 else if (&_contentView != NULL)
964 player = &_contentView;
965 else
966 player = NULL;
967 UIView *layer(player == NULL ? nil : *player);
968
969 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
970 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
971 [window setContentView:content];
972
973 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
974 [window setBackgroundColor:[_window backgroundColor]];
975 [_window setBackgroundColor:[UIColor clearColor]];
976
977 [window setLevel:-1000];
978 [window setHidden:NO];
979
980 /*if (player != NULL)
981 *player = content;*/
982
983 [content setBackgroundColor:[layer backgroundColor]];
984 [layer setBackgroundColor:[UIColor clearColor]];
985
986 UIView *indirect;
987 if (!SummerBoard_ || !IsWild_)
988 indirect = content;
989 else {
990 CGRect bounds([content bounds]);
991 bounds.origin.y = -30;
992 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
993 [content addSubview:indirect];
994 [indirect zoomToScale:2.4];
995 }
996
997 _release(WallpaperFile_);
998 _release(WallpaperImage_);
999 _release(WallpaperPage_);
1000 _release(WallpaperURL_);
1001
1002 if (paper != nil) {
1003 NSArray *themes([NSArray arrayWithObject:paper]);
1004
1005 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1006 #if UseAVController
1007 NSError *error;
1008
1009 static AVController *controller_(nil);
1010 if (controller_ == nil) {
1011 AVQueue *queue([AVQueue avQueue]);
1012 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1013 }
1014
1015 AVQueue *queue([controller_ queue]);
1016
1017 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1018 [controller_ setLayer:[video _layer]];
1019
1020 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1021 [queue appendItem:item error:&error];
1022
1023 [controller_ play:&error];
1024 #elif UseMPMoviePlayerController
1025 NSURL *url([NSURL fileURLWithPath:path]);
1026 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1027 controller.movieControlMode = MPMovieControlModeHidden;
1028 [controller play];
1029 #else
1030 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1031 [video setMovieWithPath:path];
1032 [video setRepeatMode:1];
1033 [video setRepeatGap:-1];
1034 [video playFromBeginning];;
1035 #endif
1036
1037 [indirect addSubview:video];
1038 }
1039
1040 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1041 if (UIImage *image = $getImage$(path)) {
1042 WallpaperFile_ = [path retain];
1043 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1044 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1045 [WallpaperImage_ setAlpha:[number floatValue]];
1046 [indirect addSubview:WallpaperImage_];
1047 }
1048 }
1049
1050 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1051 CGRect bounds = [indirect bounds];
1052
1053 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1054 [view setAutoresizes:true];
1055
1056 WallpaperPage_ = [view retain];
1057 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1058
1059 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1060
1061 [view setBackgroundColor:[UIColor clearColor]];
1062 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1063 [view setDrawsBackground:NO];
1064 [[view webView] setDrawsBackground:NO];
1065
1066 [indirect addSubview:view];
1067 }
1068 }
1069
1070 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1071 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1072 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1073 if ([Manager_ fileExistsAtPath:html]) {
1074 CGRect bounds = [indirect bounds];
1075
1076 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1077 [view setAutoresizes:true];
1078
1079 NSURL *url = [NSURL fileURLWithPath:html];
1080 [view loadRequest:[NSURLRequest requestWithURL:url]];
1081
1082 [view setBackgroundColor:[UIColor clearColor]];
1083 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1084 [view setDrawsBackground:NO];
1085 [[view webView] setDrawsBackground:NO];
1086
1087 [indirect addSubview:view];
1088 }
1089 }
1090
1091 return self;
1092 }
1093 // }}}
1094
1095 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1096 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1097 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1098
1099 if (path != nil && _backgroundView != nil)
1100 path = nil;
1101
1102 _SBAwayView$updateDesktopImage$(self, sel, image);
1103
1104 if (path != nil) {
1105 CGRect bounds = [self bounds];
1106
1107 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1108 [view setAutoresizes:true];
1109
1110 if (WallpaperPage_ != nil)
1111 [WallpaperPage_ release];
1112 WallpaperPage_ = [view retain];
1113
1114 if (WallpaperURL_ != nil)
1115 [WallpaperURL_ release];
1116 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1117
1118 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1119
1120 [[view webView] setDrawsBackground:false];
1121 [view setBackgroundColor:[UIColor clearColor]];
1122
1123 [self insertSubview:view aboveSubview:_backgroundView];
1124 }
1125 }
1126
1127 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1128 extern "C" CGColorRef CGGStateGetFillColor(void *);
1129 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1130 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1131
1132 /* WBTimeLabel {{{ */
1133 @interface WBTimeLabel : NSProxy {
1134 NSString *time_;
1135 _transient SBStatusBarTimeView *view_;
1136 }
1137
1138 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1139
1140 @end
1141
1142 @implementation WBTimeLabel
1143
1144 - (void) dealloc {
1145 [time_ release];
1146 [super dealloc];
1147 }
1148
1149 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1150 time_ = [time retain];
1151 view_ = view;
1152 return self;
1153 }
1154
1155 - (NSString *) description {
1156 return time_;
1157 }
1158
1159 WBDelegate(time_)
1160
1161 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1162 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1163 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1164
1165 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1166 "font-family: Helvetica; "
1167 "font-weight: bold; "
1168 "font-size: 14px; "
1169 "color: %@; "
1170 "%@", _mode ? @"white" : @"black", custom]];
1171
1172 return CGSizeZero;
1173 }
1174
1175 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1176 }
1177
1178 @end
1179 /* }}} */
1180 /* WBBadgeLabel {{{ */
1181 @interface WBBadgeLabel : NSProxy {
1182 NSString *badge_;
1183 }
1184
1185 - (id) initWithBadge:(NSString *)badge;
1186 - (NSString *) description;
1187
1188 @end
1189
1190 @implementation WBBadgeLabel
1191
1192 - (void) dealloc {
1193 [badge_ release];
1194 [super dealloc];
1195 }
1196
1197 - (id) initWithBadge:(NSString *)badge {
1198 badge_ = [badge retain];
1199 return self;
1200 }
1201
1202 - (NSString *) description {
1203 return [badge_ description];
1204 }
1205
1206 WBDelegate(badge_)
1207
1208 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1209 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1210 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1211 "font-family: Helvetica; "
1212 "font-weight: bold; "
1213 "font-size: 17px; "
1214 "color: white; "
1215 "%@", custom]];
1216
1217 return CGSizeZero;
1218 }
1219
1220 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1221 }
1222
1223 @end
1224 /* }}} */
1225
1226 // IconAlpha {{{
1227 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1228 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1229 alpha = [number floatValue];
1230 return MSOldCall(alpha);
1231 }
1232
1233 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1234 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1235 alpha = [number floatValue];
1236 return MSOldCall(alpha);
1237 }
1238
1239 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1240 if ((self = MSOldCall()) != nil) {
1241 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1242 // XXX: note: this is overridden above, which is silly
1243 float alpha([number floatValue]);
1244 [self setIconImageAlpha:alpha];
1245 [self setIconLabelAlpha:alpha];
1246 }
1247 } return self;
1248 }
1249
1250 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1251 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1252 alpha = [number floatValue];
1253 return MSOldCall(alpha);
1254 }
1255 // }}}
1256
1257 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1258 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1259 id &_badge(MSHookIvar<id>(self, "_badge"));
1260 if (_badge != nil)
1261 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1262 _badge = label;
1263 } return self;
1264 }
1265
1266 void SBStatusBarController$setStatusBarMode(int &mode) {
1267 if (Debug_)
1268 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1269 if (mode < 100) // 104:hidden 105:glowing
1270 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1271 mode = [number intValue];
1272 }
1273
1274 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1275 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1276 SBStatusBarController$setStatusBarMode(mode);
1277 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1278 }*/
1279
1280 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1281 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1282 SBStatusBarController$setStatusBarMode(mode);
1283 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1284 }
1285
1286 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int fenceID, int animation, double startTime) {
1287 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1288 SBStatusBarController$setStatusBarMode(mode);
1289 //NSLog(@"mode=%u", mode);
1290 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1291 }
1292
1293 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1294 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1295 mode = [number intValue];
1296 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1297 }*/
1298
1299 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1300 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1301 if (Debug_)
1302 NSLog(@"operatorNameStyle= %@", style);
1303 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1304 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1305 return style;
1306 }
1307
1308 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1309 if (Debug_)
1310 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1311 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1312 }
1313
1314 // XXX: replace this with [SBStatusBarTimeView tile]
1315 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1316 id &_time(MSHookIvar<id>(self, "_time"));
1317 if (_time != nil && [_time class] != [WBTimeLabel class])
1318 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1319 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1320 }
1321
1322 @interface UIView (WinterBoard)
1323 - (bool) wb$isWBImageView;
1324 - (void) wb$logHierarchy;
1325 - (void) wb$setBackgroundColor:(UIColor *)color;
1326 @end
1327
1328 @implementation UIView (WinterBoard)
1329
1330 - (bool) wb$isWBImageView {
1331 return false;
1332 }
1333
1334 - (void) wb$logHierarchy {
1335 WBLogHierarchy(self);
1336 }
1337
1338 - (void) wb$setBackgroundColor:(UIColor *)color {
1339 [self setBackgroundColor:color];
1340 for (UIView *child in [self subviews])
1341 [child wb$setBackgroundColor:color];
1342 }
1343
1344 @end
1345
1346 @interface WBImageView : UIImageView {
1347 }
1348
1349 - (bool) wb$isWBImageView;
1350 - (void) wb$updateFrame;
1351 @end
1352
1353 @implementation WBImageView
1354
1355 - (bool) wb$isWBImageView {
1356 return true;
1357 }
1358
1359 - (void) wb$updateFrame {
1360 CGRect frame([self frame]);
1361 frame.origin.y = 0;
1362
1363 for (UIView *view(self); ; ) {
1364 view = [view superview];
1365 if (view == nil)
1366 break;
1367 frame.origin.y -= [view frame].origin.y;
1368 }
1369
1370 [self setFrame:frame];
1371 }
1372
1373 @end
1374
1375 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1376 NSArray *subviews([self subviews]);
1377 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1378 if (view != nil && [view wb$isWBImageView])
1379 [view wb$updateFrame];
1380 _SBIconList$setFrame$(self, sel, frame);
1381 }
1382
1383 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1384 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1385 NSArray *lists([_iconModel iconLists]);
1386
1387 for (unsigned i(0), e([lists count]); i != e; ++i)
1388 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]])) {
1389 SBIconList *list([lists objectAtIndex:i]);
1390 NSArray *subviews([list subviews]);
1391
1392 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1393 if (view == nil || ![view wb$isWBImageView]) {
1394 view = [[[WBImageView alloc] init] autorelease];
1395 [list insertSubview:view atIndex:0];
1396 }
1397
1398 UIImage *image([UIImage imageWithContentsOfFile:path]);
1399
1400 CGRect frame([view frame]);
1401 frame.size = [image size];
1402 [view setFrame:frame];
1403
1404 [view setImage:image];
1405 [view wb$updateFrame];
1406 }
1407
1408 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1409 }
1410
1411 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1412 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1413 if (self != nil)
1414 [self setClipsToBounds:NO];
1415 return self;
1416 }
1417
1418 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1419 static bool gssc(false);
1420 if (!gssc) {
1421 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1422 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1423 gssc = true;
1424
1425 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1426 [Info_ setObject:[NSNumber numberWithBool:(
1427 !Papered_ ||
1428 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1429 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1430 )] forKey:@"UndockedIconLabels"];
1431 }
1432
1433 id &_label(MSHookIvar<id>(self, "_label"));
1434 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1435 docked = true;
1436
1437 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1438 [_label setInDock:docked];
1439
1440 _SBIconLabel$setInDock$(self, sel, docked);
1441 [self setNeedsDisplay];
1442 }
1443
1444 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1445 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1446 }
1447
1448 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1449 _SBDockIconListView$setFrame$(self, sel, frame);
1450 }
1451
1452 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1453 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1454 NSString *identifier = [self bundleIdentifier];
1455 NSLocale *locale = [NSLocale currentLocale];
1456 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1457 if (Debug_)
1458 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1459 NSString *file = table == nil ? @"Localizable" : table;
1460 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1461 NSDictionary *strings;
1462 if ((strings = [Strings_ objectForKey:name]) != nil) {
1463 if (static_cast<id>(strings) != [NSNull null]) strings:
1464 if (NSString *value = [strings objectForKey:key])
1465 return value;
1466 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1467 language, file
1468 ], self, false)) {
1469 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1470 [Strings_ setObject:[strings autorelease] forKey:name];
1471 goto strings;
1472 } else goto null;
1473 } else null:
1474 [Strings_ setObject:[NSNull null] forKey:name];
1475 return MSOldCall(key, value, table);
1476 }
1477 // }}}
1478 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1479 MSClassHook(WebCoreFrameBridge)
1480
1481 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1482 if (node == nil)
1483 return CGSizeZero;
1484 void **core(reinterpret_cast<void **>([node _node]));
1485 if (core == NULL || core[6] == NULL)
1486 return CGSizeZero;
1487 return MSOldCall(node, width);
1488 }
1489 // }}}
1490
1491 MSInstanceMessageHook1(void, SBIconLabel, drawRect, CGRect, rect) {
1492 CGRect bounds = [self bounds];
1493
1494 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1495
1496 int docked;
1497 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1498 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1499
1500 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1501
1502 NSString *style = [NSString stringWithFormat:@""
1503 "font-family: Helvetica; "
1504 "font-weight: bold; "
1505 "color: %@; %@"
1506 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1507 ? @"font-size: 12px; "
1508 : @"font-size: 11px; "
1509 )];
1510
1511 if (IsWild_)
1512 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1513 else if (docked)
1514 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1515
1516 bool ellipsis(false);
1517 float max = [self frame].size.width - 11, width;
1518 width:
1519 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
1520
1521 if (width > max) {
1522 size_t length([label length]);
1523 float spacing((width - max) / (length - 1));
1524
1525 if (spacing > 1.25) {
1526 ellipsis = true;
1527 label = [label substringToIndex:(length - 1)];
1528 goto width;
1529 }
1530
1531 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
1532 }
1533
1534 if (ellipsis)
1535 label = [label stringByAppendingString:@"..."];
1536
1537 if (NSString *custom = [Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")])
1538 style = [style stringByAppendingString:custom];
1539
1540 CGSize size = [label sizeWithStyle:style forWidth:bounds.size.width];
1541 [label drawAtPoint:CGPointMake((bounds.size.width - size.width) / 2, 0) withStyle:style];
1542 }
1543
1544 // ChatKit {{{
1545 MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1546 if ((self = MSOldCall(frame, delegate)) != nil) {
1547 [self setBackgroundColor:[UIColor clearColor]];
1548 } return self;
1549 }
1550
1551 MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1552 return SMSBackgrounded_ ? NO : MSOldCall();
1553 }
1554
1555 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1556 [self wb$setBackgroundColor:[UIColor clearColor]];
1557 return MSOldCall();
1558 }
1559
1560 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1561 MSOldCall(balloon);
1562 [balloon setBackgroundColor:[UIColor clearColor]];
1563 }
1564
1565 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1566 MSOldCall([UIColor clearColor]);
1567 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1568 }
1569
1570 // iOS >= 5.0
1571 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1572 if ((self = MSOldCall(style, reuse)) != nil) {
1573 [self setBackgroundColor:[UIColor clearColor]];
1574 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1575 } return self;
1576 }
1577
1578 // iOS << 5.0
1579 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1580 if ((self = MSOldCall(style, reuse)) != nil) {
1581 [self setBackgroundColor:[UIColor clearColor]];
1582 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1583 } return self;
1584 }
1585
1586 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1587 if ((self = MSOldCall(style, reuse)) != nil) {
1588 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1589 [_label setBackgroundColor:[UIColor clearColor]];
1590 } return self;
1591 }
1592
1593 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1594 MSOldCall(UITableViewCellSeparatorStyleNone);
1595 }
1596
1597 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1598 if ((self = MSOldCall(frame, style)) != nil) {
1599 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1600 } return self;
1601 }
1602
1603 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1604 MSOldCall();
1605
1606 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1607 if (UIImage *image = $getImage$(path)) {
1608 SMSBackgrounded_ = true;
1609
1610 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1611 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1612 UIView *table;
1613 if (&_transcriptTable != NULL)
1614 table = _transcriptTable;
1615 else if (&_transcriptLayer != NULL)
1616 table = _transcriptLayer;
1617 else
1618 table = nil;
1619
1620 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1621 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1622
1623 if (table == nil)
1624 [placard insertSubview:background atIndex:0];
1625 else {
1626 [table setBackgroundColor:[UIColor clearColor]];
1627 [placard insertSubview:background belowSubview:table];
1628 }
1629 }
1630 }
1631 // }}}
1632
1633 // %hook _UIImageWithName() {{{
1634 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1635 if (Debug_)
1636 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1637 if (name == nil)
1638 return nil;
1639
1640 int identifier;
1641 bool packed;
1642
1643 if (_UIPackedImageTableGetIdentifierForName != NULL)
1644 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1645 else if (_UISharedImageNameGetIdentifier != NULL) {
1646 identifier = _UISharedImageNameGetIdentifier(name);
1647 packed = identifier != -1;
1648 } else {
1649 identifier = -1;
1650 packed = false;
1651 }
1652
1653 if (Debug_)
1654 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1655
1656 if (!packed)
1657 return __UIImageWithName(name);
1658 else {
1659 NSNumber *key([NSNumber numberWithInt:identifier]);
1660 UIImage *image([UIImages_ objectForKey:key]);
1661 if (image != nil)
1662 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1663 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1664 image = $getImage$(path);
1665 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1666 if (image != nil)
1667 return image;
1668
1669 image = __UIImageWithName(name);
1670
1671 if (UIDebug_) {
1672 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1673 if (![Manager_ fileExistsAtPath:path])
1674 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1675 }
1676
1677 return image;
1678 }
1679 }
1680 // }}}
1681 // %hook _UIImageWithNameInDomain() {{{
1682 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1683 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1684 UIImage *image([PathImages_ objectForKey:key]);
1685 if (image != nil)
1686 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1687 if (Debug_)
1688 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1689 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1690 image = $getImage$(path);
1691 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1692 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1693 }
1694 // }}}
1695
1696 // %hook GSFontCreateWithName() {{{
1697 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1698 if (Debug_)
1699 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1700 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1701 name = [font UTF8String];
1702 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1703 // size *= [scale floatValue];
1704 return _GSFontCreateWithName(name, traits, size);
1705 }
1706 // }}}
1707
1708 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1709 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1710
1711 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1712
1713 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1714 if (Debug_)
1715 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1716 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1717 if (Debug_)
1718 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1719
1720 if (value) {
1721 NSString *path = [NSString stringWithUTF8String:a1];
1722 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1723 NSString *file = [path substringFromIndex:31];
1724 for (NSString *theme in Themes_) {
1725 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1726 if ([Manager_ fileExistsAtPath:path]) {
1727 strcpy(a1, [path UTF8String]);
1728 continue;
1729 }
1730 }
1731 }
1732 }
1733 return value;
1734 }
1735
1736 static void ChangeWallpaper(
1737 CFNotificationCenterRef center,
1738 void *observer,
1739 CFStringRef name,
1740 const void *object,
1741 CFDictionaryRef info
1742 ) {
1743 if (Debug_)
1744 NSLog(@"WB:Debug:ChangeWallpaper!");
1745
1746 UIImage *image;
1747 if (WallpaperFile_ != nil) {
1748 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1749 if (image != nil)
1750 image = [image autorelease];
1751 } else image = nil;
1752
1753 if (WallpaperImage_ != nil)
1754 [WallpaperImage_ setImage:image];
1755 if (WallpaperPage_ != nil)
1756 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1757
1758 }
1759
1760 #define WBRename(name, sel, imp) \
1761 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
1762
1763 template <typename Type_>
1764 static void msset(Type_ &function, MSImageRef image, const char *name) {
1765 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1766 }
1767
1768 template <typename Type_>
1769 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1770 struct nlist &name(nl[index]);
1771 uintptr_t value(name.n_value);
1772 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1773 value |= 0x00000001;
1774 function = reinterpret_cast<Type_>(value);
1775 }
1776
1777 template <typename Type_>
1778 static void dlset(Type_ &function, const char *name) {
1779 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1780 }
1781
1782 // %hook CGImageReadCreateWithFile() {{{
1783 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1784 if (Debug_)
1785 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1786 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1787 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1788 [pool release];
1789 return value;
1790 }
1791 // }}}
1792
1793 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
1794 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1795 if (style == nil || [style length] == 0)
1796 style = @"font-family: Helvetica; font-size: 12px";
1797 return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
1798 }
1799
1800 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
1801 if (style == nil || [style length] == 0)
1802 style = @"font-family: Helvetica; font-size: 12px";
1803 return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width];
1804 }
1805
1806 static void SBInitialize() {
1807 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
1808 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
1809
1810 if (SummerBoard_) {
1811 WBRename(SBApplication, pathForIcon, pathForIcon);
1812 WBRename(SBApplicationIcon, icon, icon);
1813 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1814 }
1815
1816 WBRename(SBBookmarkIcon, icon, icon);
1817 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1818 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1819 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1820 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
1821
1822 WBRename(SBWidgetApplicationIcon, icon, icon);
1823
1824 WBRename(SBDockIconListView, setFrame:, setFrame$);
1825 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
1826
1827 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
1828 WBRename(SBIconLabel, setInDock:, setInDock$);
1829
1830 WBRename(SBIconList, setFrame:, setFrame$);
1831
1832 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
1833 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
1834 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
1835 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
1836
1837 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
1838 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
1839 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
1840
1841 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
1842
1843 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
1844 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
1845 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
1846 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
1847 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
1848 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
1849 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
1850 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
1851 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
1852
1853 if (SummerBoard_)
1854 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
1855 }
1856
1857 MSInitialize {
1858 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1859
1860 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
1861 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
1862
1863 Manager_ = [[NSFileManager defaultManager] retain];
1864 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
1865
1866 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
1867
1868 // Load Settings.plist {{{
1869 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
1870 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
1871 SummerBoard_ = [value boolValue];
1872 if (NSNumber *value = [settings objectForKey:@"Debug"])
1873 Debug_ = [value boolValue];
1874 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
1875 UIDebug_ = [value boolValue];
1876
1877 NSArray *themes([settings objectForKey:@"Themes"]);
1878 if (themes == nil)
1879 if (NSString *theme = [settings objectForKey:@"Theme"])
1880 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
1881 theme, @"Name",
1882 [NSNumber numberWithBool:true], @"Active",
1883 nil]];
1884
1885 if (themes != nil)
1886 for (NSDictionary *theme in themes) {
1887 NSNumber *active([theme objectForKey:@"Active"]);
1888 if (![active boolValue])
1889 continue;
1890
1891 NSString *name([theme objectForKey:@"Name"]);
1892 if (name == nil)
1893 continue;
1894
1895 NSString *theme(nil);
1896
1897 #define testForTheme(format...) \
1898 if (theme == nil) { \
1899 NSString *path = [NSString stringWithFormat:format]; \
1900 if ([Manager_ fileExistsAtPath:path]) { \
1901 [Themes_ addObject:path]; \
1902 continue; \
1903 } \
1904 }
1905
1906 testForTheme(@"/Library/Themes/%@.theme", name)
1907 testForTheme(@"/Library/Themes/%@", name)
1908 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
1909
1910 }
1911 }
1912 // }}}
1913 // Merge Info.plist {{{
1914 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1915
1916 for (NSString *theme in Themes_)
1917 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
1918 for (NSString *key in [info allKeys])
1919 if ([Info_ objectForKey:key] == nil)
1920 [Info_ setObject:[info objectForKey:key] forKey:key];
1921 // }}}
1922
1923 // AudioToolbox {{{
1924 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
1925 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
1926 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
1927 }
1928 // }}}
1929 // GraphicsServices {{{
1930 if (true) {
1931 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
1932 }
1933 // }}}
1934 // ImageIO {{{
1935 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
1936 void *(*CGImageReadCreateWithFile)(NSString *, int);
1937 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
1938 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
1939 }
1940 // }}}
1941 // SpringBoard {{{
1942 if (SpringBoard_) {
1943 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
1944 Papered_ = $getTheme$(Wallpapers_) != nil;
1945 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
1946
1947 CFNotificationCenterAddObserver(
1948 CFNotificationCenterGetDarwinNotifyCenter(),
1949 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
1950 );
1951
1952 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
1953 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
1954 if (MediaPlayer != nil)
1955 [MediaPlayer load];
1956
1957 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
1958 $MPVideoView = objc_getClass("MPVideoView");
1959 }
1960
1961 SBInitialize();
1962 }
1963 // }}}
1964 // UIKit {{{
1965 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
1966 struct nlist nl[6];
1967 memset(nl, 0, sizeof(nl));
1968 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
1969 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
1970 nl[2].n_un.n_name = (char *) "__UIKitBundle";
1971 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
1972 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
1973 nlist(UIKit, nl);
1974
1975 nlset(_UIApplicationImageWithName, nl, 0);
1976 nlset(_UIImageWithNameInDomain, nl, 1);
1977 nlset(_UIKitBundle, nl, 2);
1978 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
1979 nlset(_UISharedImageNameGetIdentifier, nl, 4);
1980
1981 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
1982 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
1983 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
1984 }
1985 // }}}
1986
1987 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
1988 NSError *error(nil);
1989 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
1990 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
1991 nil] error:&error])
1992 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);
1993 }
1994
1995 [pool release];
1996 }