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