]> git.saurik.com Git - winterboard.git/blob - Library.mm
219f4e7633f5516646ecef1dfec0e1cda0abafd6
[winterboard.git] / Library.mm
1 /* WinterBoard - Theme Manager for the iPhone
2 * Copyright (C) 2008-2014 Jay Freeman (saurik)
3 */
4
5 /* GNU Lesser General Public License, Version 3 {{{ */
6 /*
7 * WinterBoard is free software: you can redistribute it and/or modify it under
8 * the terms of the GNU Lesser General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * WinterBoard is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 * License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with WinterBoard. If not, see <http://www.gnu.org/licenses/>.
19 **/
20 /* }}} */
21
22 #include <sys/time.h>
23
24 struct timeval _ltv;
25 bool _itv;
26
27 #define _trace() do { \
28 struct timeval _ctv; \
29 gettimeofday(&_ctv, NULL); \
30 if (!_itv) { \
31 _itv = true; \
32 _ltv = _ctv; \
33 } \
34 NSLog(@"%lu.%.6u[%f]:WB:_trace()@%s:%u[%s]\n", \
35 _ctv.tv_sec, _ctv.tv_usec, \
36 (_ctv.tv_sec - _ltv.tv_sec) + (_ctv.tv_usec - _ltv.tv_usec) / 1000000.0, \
37 __FILE__, __LINE__, __FUNCTION__\
38 ); \
39 _ltv = _ctv; \
40 } while (false)
41
42 #define _transient
43
44 #import <CoreFoundation/CoreFoundation.h>
45 #import <Foundation/Foundation.h>
46 #import <CoreGraphics/CoreGraphics.h>
47 #import <ImageIO/CGImageSource.h>
48
49 #import <Celestial/AVController.h>
50 #import <Celestial/AVItem.h>
51 #import <Celestial/AVQueue.h>
52
53 #include <substrate.h>
54
55 #import <UIKit/UIKit.h>
56
57 #import <SpringBoard/SBApplication.h>
58 #import <SpringBoard/SBApplicationIcon.h>
59 #import <SpringBoard/SBAppWindow.h>
60 #import <SpringBoard/SBAwayView.h>
61 #import <SpringBoard/SBBookmarkIcon.h>
62 #import <SpringBoard/SBButtonBar.h>
63 #import <SpringBoard/SBCalendarIconContentsView.h>
64 #import <SpringBoard/SBIconController.h>
65 #import <SpringBoard/SBIconLabel.h>
66 #import <SpringBoard/SBIconList.h>
67 #import <SpringBoard/SBIconModel.h>
68 #import <SpringBoard/SBImageCache.h>
69 // XXX: #import <SpringBoard/SBSearchView.h>
70 #import <SpringBoard/SBSearchTableViewCell.h>
71 #import <SpringBoard/SBStatusBarContentsView.h>
72 #import <SpringBoard/SBStatusBarController.h>
73 #import <SpringBoard/SBStatusBarOperatorNameView.h>
74 #import <SpringBoard/SBStatusBarTimeView.h>
75 #import <SpringBoard/SBUIController.h>
76 #import <SpringBoard/SBWidgetApplicationIcon.h>
77
78 #import <MobileSMS/mSMSMessageTranscriptController.h>
79
80 #import <MediaPlayer/MPMoviePlayerController.h>
81 #import <MediaPlayer/MPVideoView.h>
82 #import <MediaPlayer/MPVideoView-PlaybackControl.h>
83
84 #import <CoreGraphics/CGGeometry.h>
85
86 #import <ChatKit/CKMessageCell.h>
87
88 #include <sys/sysctl.h>
89
90 #include "WBMarkup.h"
91
92 static void (*$objc_setAssociatedObject)(id object, void *key, id value, objc_AssociationPolicy policy);
93 static id (*$objc_getAssociatedObject)(id object, void *key);
94 static void (*$objc_removeAssociatedObjects)(id object);
95
96 @protocol WinterBoard
97 - (void *) _node;
98 @end
99
100 Class $MPMoviePlayerController;
101 Class $MPVideoView;
102
103 MSClassHook(NSBundle)
104 MSClassHook(NSString)
105
106 MSClassHook(_UIAssetManager)
107 MSClassHook(UIImage)
108 MSMetaClassHook(UIImage)
109 MSClassHook(UINavigationBar)
110 MSClassHook(UISharedArtwork)
111 MSClassHook(UIToolbar)
112 MSClassHook(UIStatusBarTimeItemView)
113 MSClassHook(UIWebDocumentView)
114
115 MSClassHook(CKBalloonView)
116 MSClassHook(CKMessageCell)
117 MSClassHook(CKTimestampView)
118 MSClassHook(CKTranscriptCell)
119 MSClassHook(CKTranscriptController)
120 MSClassHook(CKTranscriptHeaderView)
121 MSClassHook(CKTranscriptTableView)
122
123 MSClassHook(SBApplication)
124 MSClassHook(SBApplicationIcon)
125 MSClassHook(SBAwayView)
126 MSClassHook(SBBookmarkIcon)
127 MSClassHook(SBButtonBar)
128 MSClassHook(SBCalendarApplicationIcon)
129 MSClassHook(SBCalendarIconContentsView)
130 MSClassHook(SBDockIconListView)
131 MSClassHook(SBIcon)
132 MSClassHook(SBIconAccessoryImage)
133 MSMetaClassHook(SBIconAccessoryImage)
134 MSClassHook(SBIconBadge)
135 MSClassHook(SBIconBadgeFactory)
136 MSClassHook(SBIconBadgeImage)
137 MSClassHook(SBIconBadgeView)
138 MSMetaClassHook(SBIconBadgeView)
139 MSClassHook(SBIconContentView)
140 MSClassHook(SBIconController)
141 MSClassHook(SBIconLabel)
142 MSClassHook(SBIconLabelImage)
143 MSMetaClassHook(SBIconLabelImage)
144 MSClassHook(SBIconLabelImageParameters)
145 MSClassHook(SBIconList)
146 MSClassHook(SBIconModel)
147 MSClassHook(SBIconView)
148 MSMetaClassHook(SBIconView)
149 //MSClassHook(SBImageCache)
150 MSClassHook(SBSearchView)
151 MSClassHook(SBSearchTableViewCell)
152 MSClassHook(SBSlidingAlertDisplay)
153 MSClassHook(SBStatusBarContentsView)
154 MSClassHook(SBStatusBarController)
155 MSClassHook(SBStatusBarOperatorNameView)
156 MSClassHook(SBStatusBarTimeView)
157 MSClassHook(SBUIController)
158 MSClassHook(SBWallpaperView)
159 MSClassHook(SBWidgetApplicationIcon)
160
161 extern "C" void WKSetCurrentGraphicsContext(CGContextRef);
162
163 static struct MSFixClass { MSFixClass() {
164 $UIWebDocumentView = objc_getClass("UIWebBrowserView") ?: $UIWebDocumentView;
165 $SBIcon = objc_getClass("SBIconView") ?: $SBIcon;
166
167 if ($SBIconList == nil)
168 $SBIconList = objc_getClass("SBIconListView");
169 if ($CKTranscriptController == nil)
170 $CKTranscriptController = objc_getClass("mSMSMessageTranscriptController");
171 } } MSFixClass;
172
173 static bool IsWild_;
174 static bool Four_($SBDockIconListView != nil);
175
176 @interface NSObject (wb$SBIconAccessoryImage)
177 + (Class) _imageClassForIcon:(SBIcon *)icon location:(int)location;
178 @end
179
180 @interface NSDictionary (WinterBoard)
181 - (UIColor *) wb$colorForKey:(NSString *)key;
182 - (BOOL) wb$boolForKey:(NSString *)key;
183 @end
184
185 @implementation NSDictionary (WinterBoard)
186
187 - (UIColor *) wb$colorForKey:(NSString *)key {
188 NSString *value = [self objectForKey:key];
189 if (value == nil)
190 return nil;
191 /* XXX: incorrect */
192 return nil;
193 }
194
195 - (BOOL) wb$boolForKey:(NSString *)key {
196 if (NSString *value = [self objectForKey:key])
197 return [value boolValue];
198 return false;
199 }
200
201 @end
202
203 @interface _UIAssetManager : NSObject
204 - (NSBundle *) bundle;
205 - (NSString *) carFileName;
206 @end
207
208 static BOOL (*_GSFontGetUseLegacyFontMetrics)();
209 #define $GSFontGetUseLegacyFontMetrics() \
210 (_GSFontGetUseLegacyFontMetrics == NULL ? YES : _GSFontGetUseLegacyFontMetrics())
211
212 static bool Debug_ = false;
213 static bool UIDebug_ = false;
214 static bool Engineer_ = false;
215 static bool SummerBoard_ = false;
216 static bool SpringBoard_;
217
218 static UIImage *(*_UIApplicationImageWithName)(NSString *name);
219 static UIImage *(*_UIImageWithNameInDomain)(NSString *name, NSString *domain);
220 static NSBundle *(*_UIKitBundle)();
221
222 static NSMutableDictionary *Images_ = [[NSMutableDictionary alloc] initWithCapacity:64];
223 static NSMutableDictionary *Cache_ = [[NSMutableDictionary alloc] initWithCapacity:64];
224 static NSMutableDictionary *Strings_ = [[NSMutableDictionary alloc] initWithCapacity:0];
225 static NSMutableDictionary *Bundles_ = [[NSMutableDictionary alloc] initWithCapacity:2];
226
227 static NSFileManager *Manager_;
228 static NSMutableArray *Themes_;
229
230 static NSDictionary *English_;
231 static NSMutableDictionary *Info_;
232
233 // @interface WBBundle {{{
234 @interface WBBundle : NSBundle {
235 NSString *identifier_;
236 }
237
238 + (WBBundle *) bundleWithIdentifier:(NSString *)identifier;
239
240 @end
241
242 @implementation WBBundle
243
244 - (void) dealloc {
245 [identifier_ release];
246 return [super dealloc];
247 }
248
249 + (WBBundle *) bundleWithIdentifier:(NSString *)identifier {
250 return [[[self alloc] initWithIdentifier:identifier] autorelease];
251 }
252
253 - (id) initWithIdentifier:(NSString *)identifier {
254 if ((self = [super init]) != nil) {
255 identifier_ = [identifier retain];
256 } return self;
257 }
258
259 - (NSString *) bundleIdentifier {
260 return identifier_;
261 }
262
263 @end
264 // }}}
265
266 // $getTheme$() {{{
267 static NSMutableDictionary *Themed_ = [[NSMutableDictionary alloc] initWithCapacity:128];
268
269 static unsigned Scale_ = 0;
270
271 static unsigned $getScale$(NSString *path) {
272 NSString *name(path);
273
274 #define StripName(strip) \
275 if ([name hasSuffix:@ strip]) \
276 name = [name substringWithRange:NSMakeRange(0, [name length] - sizeof(strip) - 1)];
277
278 StripName(".png");
279 StripName(".jpg");
280 StripName("~iphone");
281 StripName("~ipad");
282
283 if ([name hasSuffix:@"@3x"])
284 return 3;
285 if ([name hasSuffix:@"@2x"])
286 return 2;
287 return 1;
288 }
289
290 static NSArray *$useScale$(NSArray *files, bool use = true) {
291 if (use && Scale_ == 0) {
292 UIScreen *screen([UIScreen mainScreen]);
293 if ([screen respondsToSelector:@selector(scale)])
294 Scale_ = [screen scale];
295 else
296 Scale_ = 1;
297 }
298
299 NSString *idiom(IsWild_ ? @"ipad" : @"iphone");
300
301 NSMutableArray *scaled([NSMutableArray arrayWithCapacity:([files count] * 6)]);
302
303 for (NSString *file in files) {
304 NSString *base([file stringByDeletingPathExtension]);
305 NSString *extension([file pathExtension]);
306
307 #define WBScaleImage(scale) \
308 if (scale == 1) { \
309 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]]; \
310 [scaled addObject:file]; \
311 } else { \
312 [scaled addObject:[NSString stringWithFormat:@"%@@%ux~%@.%@", base, scale, idiom, extension]]; \
313 [scaled addObject:[NSString stringWithFormat:@"%@@%ux.%@", base, scale, extension]]; \
314 }
315
316 if (use) {
317 WBScaleImage(Scale_);
318
319 for (unsigned scale(3); scale >= 1; --scale)
320 if (scale != Scale_)
321 WBScaleImage(scale);
322 } else if ([base hasSuffix: @"@2x"] || [base hasSuffix:@"@3x"]) {
323 WBScaleImage(1);
324
325 // XXX: this actually can't be used, as the person loading the file doesn't realize that the @2x changed
326 /*NSString *rest([base substringWithRange:NSMakeRange(0, [base length] - 3)]);
327 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", rest, idiom, extension]];
328 [scaled addObject:[rest stringByAppendingPathExtension:extension]];*/
329 } else {
330 // XXX: this code isn't really complete
331
332 [scaled addObject:file];
333
334 if ([base hasSuffix:[NSString stringWithFormat:@"~%@", idiom]])
335 [scaled addObject:[[base substringWithRange:NSMakeRange(0, [base length] - 1 - [idiom length])] stringByAppendingPathExtension:extension]];
336 }
337 }
338
339 return scaled;
340 }
341
342 static NSString *$getTheme$(NSArray *files, NSArray *themes = Themes_) {
343 // XXX: this is not reasonable; OMG
344 id key(files);
345
346 @synchronized (Themed_) {
347 if (NSString *path = [Themed_ objectForKey:key])
348 return reinterpret_cast<id>(path) == [NSNull null] ? nil : path;
349 }
350
351 if (Debug_)
352 NSLog(@"WB:Debug: %@", [files description]);
353
354 NSString *path;
355
356 for (NSString *theme in Themes_)
357 for (NSString *file in files) {
358 path = [NSString stringWithFormat:@"%@/%@", theme, file];
359 if ([Manager_ fileExistsAtPath:path]) {
360 if ([[Manager_ destinationOfSymbolicLinkAtPath:path error:NULL] isEqualToString:@"/"])
361 path = nil;
362 goto set;
363 }
364 }
365
366 path = nil;
367 set:
368
369 @synchronized (Themed_) {
370 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:key];
371 }
372
373 return path;
374 }
375 // }}}
376 // $pathForFile$inBundle$() {{{
377 static void $pathForFile$inBundle$(NSMutableArray *names, NSString *file, NSString *identifier, NSString *folder) {
378 if (identifier != nil)
379 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
380 if (folder != nil) {
381 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
382 NSString *base([folder stringByDeletingPathExtension]);
383 if ([base hasSuffix:@"~iphone"])
384 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 7)], [folder pathExtension], file]];
385 if ([base hasSuffix:@"~ipad"])
386 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 5)], [folder pathExtension], file]];
387 }
388
389 #define remapResourceName(oldname, newname) \
390 else if ([file isEqualToString:(oldname)]) \
391 [names addObject:oldname ".png"];
392
393 bool summer(SpringBoard_ && SummerBoard_);
394
395 if (identifier == nil);
396 else if ([identifier isEqualToString:@"com.apple.uikit.Artwork"])
397 $pathForFile$inBundle$(names, file, @"com.apple.UIKit", @"UIKit.framework");
398 else if ([identifier isEqualToString:@"com.apple.uikit.LegacyArtwork"])
399 $pathForFile$inBundle$(names, file, @"com.apple.UIKit", @"UIKit.framework");
400 else if ([identifier isEqualToString:@"com.apple.UIKit"])
401 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
402 else if ([identifier isEqualToString:@"com.apple.chatkit"])
403 $pathForFile$inBundle$(names, file, @"com.apple.MobileSMS", @"MobileSMS.app");
404 else if ([identifier isEqualToString:@"com.apple.calculator"])
405 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
406 else if ([identifier isEqualToString:@"com.apple.Maps"] && [file isEqualToString:@"Icon-57@2x.png"])
407 $pathForFile$inBundle$(names, @"icon.png", identifier, folder);
408 else if (!summer);
409 remapResourceName(@"FSO_BG.png", @"StatusBar")
410 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
411 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
412 }
413
414 static NSString *$pathForFile$inBundle$(NSString *file, NSString *identifier, NSURL *url, bool use) {
415 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
416 $pathForFile$inBundle$(names, file, identifier, [url lastPathComponent]);
417 [names addObject:[NSString stringWithFormat:@"Fallback/%@", file]];
418 if (NSString *path = $getTheme$($useScale$(names, use)))
419 return path;
420 return nil;
421 }
422
423 // XXX: this cannot be merged due to WBBundle
424 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool use) {
425 return $pathForFile$inBundle$(file, [bundle bundleIdentifier], [bundle bundleURL], use);
426 }
427
428 static NSString *$pathForFile$inBundle$(NSString *file, CFBundleRef bundle, bool use) {
429 NSString *identifier((NSString *) CFBundleGetIdentifier(bundle));
430 NSURL *url([(NSURL *) CFBundleCopyBundleURL(bundle) autorelease]);
431 return $pathForFile$inBundle$(file, identifier, url, use);
432 }
433 // }}}
434
435 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
436 NSString *identifier = [self bundleIdentifier];
437 NSString *path = [self path];
438 NSString *folder = [path lastPathComponent];
439 NSString *dname = [self displayName];
440
441 NSString *didentifier;
442 if ([self respondsToSelector:@selector(displayIdentifier)])
443 didentifier = [self displayIdentifier];
444 else
445 didentifier = nil;
446
447 if (Debug_)
448 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
449
450 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
451
452 /* XXX: I might need to keep this for backwards compatibility
453 if (identifier != nil)
454 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
455 if (folder != nil)
456 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
457
458 #define testForIcon(Name) \
459 if (NSString *name = Name) \
460 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
461
462 if (didentifier != nil && ![didentifier isEqualToString:identifier])
463 testForIcon(didentifier);
464
465 testForIcon(identifier);
466 testForIcon(dname);
467
468 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
469 testForIcon(@"SMS");
470
471 if (didentifier != nil) {
472 testForIcon([English_ objectForKey:didentifier]);
473
474 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
475 if ([parts count] != 1)
476 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
477 testForIcon([english objectForKey:[parts lastObject]]);
478 }
479
480 if (NSString *path = $getTheme$(names))
481 return path;
482
483 return nil;
484 }
485
486 // -[NSBundle wb$bundleWithFile] {{{
487 @interface NSBundle (WinterBoard)
488 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
489 @end
490
491 @implementation NSBundle (WinterBoard)
492
493 + (NSBundle *) _wb$bundleWithFile:(NSString *)path {
494 path = [path stringByDeletingLastPathComponent];
495 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
496 return nil;
497
498 NSBundle *bundle;
499 @synchronized (Bundles_) {
500 bundle = [Bundles_ objectForKey:path];
501 }
502
503 if (reinterpret_cast<id>(bundle) == [NSNull null])
504 return nil;
505 else if (bundle == nil) {
506 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
507 bundle = [NSBundle bundleWithPath:path];
508 if (bundle == nil)
509 bundle = [NSBundle _wb$bundleWithFile:path];
510 if (Debug_)
511 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
512
513 @synchronized (Bundles_) {
514 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
515 }
516 }
517
518 return bundle;
519 }
520
521 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
522 if ([path hasPrefix:@"/Library/Themes"])
523 return nil;
524 return [self _wb$bundleWithFile:path];
525 }
526
527 @end
528 // }}}
529 // -[NSString wb$themedPath] {{{
530 @interface NSString (WinterBoard)
531 - (NSString *) wb$themedPath;
532 @end
533
534 @implementation NSString (WinterBoard)
535
536 - (NSString *) wb$themedPath {
537 if (Debug_)
538 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
539
540 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
541 NSString *file([self stringByResolvingSymlinksInPath]);
542 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
543 if ([file hasPrefix:prefix]) {
544 NSUInteger length([prefix length]);
545 if (length != [file length])
546 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
547 return path;
548 }
549 }
550
551 return self;
552 }
553
554 @end
555 // }}}
556
557 void WBLogRect(const char *tag, struct CGRect rect) {
558 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
559 }
560
561 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
562 CGRect frame([view frame]);
563 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]);
564 index = 0;
565 for (UIView *child in [view subviews])
566 WBLogHierarchy(child, index++, indent + 1);
567 }
568
569 UIImage *$cacheForImage$(UIImage *image) {
570 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
571 CGRect rect = {CGPointMake(1, 1), [image size]};
572 CGSize size = {rect.size.width + 2, rect.size.height + 2};
573
574 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
575 CGColorSpaceRelease(space);
576
577 CGContextDrawImage(context, rect, [image CGImage]);
578 CGImageRef ref(CGBitmapContextCreateImage(context));
579 CGContextRelease(context);
580
581 UIImage *cache([UIImage imageWithCGImage:ref]);
582 CGImageRelease(ref);
583
584 return cache;
585 }
586
587 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
588 //if ([name isEqualToString:@"icons"]) return nil;
589 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
590 }*/
591
592 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
593 NSString *key([icon displayIdentifier]);
594
595 if (UIImage *image = [icon icon]) {
596 CGSize size = [image size];
597 if (size.width != 59 || size.height != 60) {
598 UIImage *cache($cacheForImage$(image));
599 [Cache_ setObject:cache forKey:key];
600 return;
601 }
602 }
603
604 _SBIconModel$cacheImageForIcon$(self, sel, icon);
605 }
606
607 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
608 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
609 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
610
611 NSString *key([icon displayIdentifier]);
612
613 if (UIImage *image = [icon icon]) {
614 CGSize size = [image size];
615 if (size.width != 59 || size.height != 60) {
616 UIImage *cache($cacheForImage$(image));
617 [Cache_ setObject:cache forKey:key];
618 return;
619 }
620 }
621 }
622
623 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
624 NSString *key([icon displayIdentifier]);
625 if (UIImage *image = [Cache_ objectForKey:key])
626 return image;
627 else
628 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
629 }
630
631 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
632 if (small)
633 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
634 NSString *key([icon displayIdentifier]);
635 if (UIImage *image = [Cache_ objectForKey:key])
636 return image;
637 else
638 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
639 }
640
641 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
642 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
643 [self setBackgroundColor:[UIColor clearColor]];
644 for (UIView *child in [self subviews])
645 [child setBackgroundColor:[UIColor clearColor]];
646 } return self;
647 }
648
649 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
650 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
651 [self setBackgroundColor:[UIColor clearColor]];
652 } return self;
653 }
654
655 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
656 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
657 float inset([self edgeInset]);
658 [[UIColor clearColor] set];
659 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
660 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
661 }
662
663 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
664 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
665 if (NSString *path = $pathForIcon$([self application]))
666 return [UIImage imageWithContentsOfFile:path];
667 return _SBApplicationIcon$icon(self, sel);
668 }
669
670 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
671 if (type == 2)
672 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
673 if (IsWild_ && false) // XXX: delete this code, it should not be supported
674 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
675 return [UIImage imageWithContentsOfFile:path72];
676 if (NSString *path = $pathForIcon$([self application]))
677 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
678 CGFloat width;
679 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
680 width = [$SBIcon defaultIconImageSize].width;
681 else
682 width = 59;
683 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
684 }
685 }
686 return _SBApplicationIcon$generateIconImage$(self, sel, type);
687 }
688
689 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
690 if (Debug_)
691 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
692 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
693 return [UIImage imageWithContentsOfFile:path];
694 return _SBWidgetApplicationIcon$icon(self, sel);
695 }
696
697 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
698 if (Debug_)
699 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
700 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
701 return [UIImage imageWithContentsOfFile:path];
702 return _SBBookmarkIcon$icon(self, sel);
703 }
704
705 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
706 if (NSString *path = $pathForIcon$(self))
707 return path;
708 return _SBApplication$pathForIcon(self, sel);
709 }
710
711 static UIImage *CachedImageAtPath(NSString *path) {
712 path = [path stringByResolvingSymlinksInPath];
713 UIImage *image = [Images_ objectForKey:path];
714 if (image != nil)
715 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
716 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
717 if (image != nil)
718 image = [image autorelease];
719 [Images_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
720 return image;
721 }
722
723 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
724 NSBundle *bundle = [NSBundle mainBundle];
725 if (Debug_)
726 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
727 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
728 return CachedImageAtPath(path);
729 return __UIApplicationImageWithName(name);
730 }
731
732 #define WBDelegate(delegate) \
733 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
734 if (Engineer_) \
735 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
736 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
737 return sig; \
738 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
739 return nil; \
740 } \
741 \
742 - (void) forwardInvocation:(NSInvocation*)inv { \
743 SEL sel = [inv selector]; \
744 if ([delegate respondsToSelector:sel]) \
745 [inv invokeWithTarget:delegate]; \
746 else \
747 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
748 }
749
750 // %hook CFBundleCopyResourceURL {{{
751 MSHook(CFURLRef, CFBundleCopyResourceURL, CFBundleRef bundle, CFStringRef resourceName, CFStringRef resourceType, CFStringRef subDirName) {
752 NSString *file((NSString *) resourceName);
753 if (resourceType != NULL)
754 file = [NSString stringWithFormat:@"%@.%@", file, resourceType];
755 if (subDirName != NULL)
756 file = [NSString stringWithFormat:@"%@/%@", subDirName, resourceType];
757
758 if (![file hasSuffix:@".png"]) {
759 if (Debug_)
760 NSLog(@"WB:Debug: CFBundleCopyResourceURL(<%@>, \"%@\", \"%@\", \"%@\")", CFBundleGetIdentifier(bundle), resourceName, resourceType, subDirName);
761 if (NSString *path = $pathForFile$inBundle$(file, bundle, false))
762 return (CFURLRef) [[NSURL alloc] initFileURLWithPath:path];
763 }
764
765 return _CFBundleCopyResourceURL(bundle, resourceName, resourceType, subDirName);
766 }
767 // }}}
768
769 static void $drawLabel$(NSString *label, CGRect rect, NSString *style, NSString *custom) {
770 bool ellipsis(false);
771 CGFloat max = rect.size.width - 11, width;
772 width:
773 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
774
775 if (width > max) {
776 size_t length([label length]);
777 CGFloat spacing((width - max) / (length - 1));
778
779 if (spacing > 1.25) {
780 ellipsis = true;
781 label = [label substringToIndex:(length - 1)];
782 goto width;
783 }
784
785 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
786 }
787
788 if (ellipsis)
789 label = [label stringByAppendingString:@"..."];
790
791 if (custom != nil)
792 style = [style stringByAppendingString:custom];
793
794 CGSize size = [label sizeWithStyle:style forWidth:rect.size.width];
795 [label drawAtPoint:CGPointMake((rect.size.width - size.width) / 2 + rect.origin.x, rect.origin.y) withStyle:style];
796 }
797
798 static struct WBStringDrawingState {
799 WBStringDrawingState *next_;
800 unsigned count_;
801 NSString *base_;
802 NSString *info_;
803 } *stringDrawingState_;
804
805 extern "C" CGColorSpaceRef CGContextGetFillColorSpace(CGContextRef);
806 extern "C" void CGContextGetFillColor(CGContextRef, CGFloat[]);
807
808 static NSString *WBColorMarkup(size_t number, const CGFloat *components) {
809 CGFloat r, g, b, a;
810
811 switch (number) {
812 case 1:
813 r = components[0];
814 g = components[0];
815 b = components[0];
816 a = components[1];
817 break;
818
819 case 3:
820 r = components[0];
821 g = components[1];
822 b = components[2];
823 a = components[3];
824 break;
825
826 default:
827 return @"";
828 }
829
830 return [NSString stringWithFormat:@"color: rgba(%g, %g, %g, %g)", r * 255, g * 255, b * 255, a];
831 }
832
833 static NSString *WBColorMarkup() {
834 CGContextRef context(UIGraphicsGetCurrentContext());
835 //NSLog(@"XXX:1:%p", context);
836 if (context == NULL)
837 return @"";
838
839 CGColorSpaceRef space(CGContextGetFillColorSpace(context));
840 //NSLog(@"XXX:2:%p", space);
841 if (space == NULL)
842 return @"";
843
844 size_t number(CGColorSpaceGetNumberOfComponents(space));
845 //NSLog(@"XXX:3:%u", number);
846 if (number == 0)
847 return @"";
848
849 CGFloat components[number + 1];
850 CGContextGetFillColor(context, components);
851 return WBColorMarkup(number, components);
852 }
853
854 static NSString *WBColorMarkup(UIColor *uicolor) {
855 if (uicolor == nil)
856 return @"";
857 CGColorRef cgcolor([uicolor CGColor]);
858 if (cgcolor == NULL)
859 return @"";
860
861 CGColorSpaceRef space(CGColorGetColorSpace(cgcolor));
862 //NSLog(@"XXX:2:%p", space);
863 if (space == NULL)
864 return @"";
865
866 size_t number(CGColorGetNumberOfComponents(cgcolor));
867 //NSLog(@"XXX:3:%u", number);
868 if (number == 0)
869 return @"";
870
871 const CGFloat *components(CGColorGetComponents(cgcolor));
872 return WBColorMarkup(number, components);
873 }
874
875 extern "C" NSString *NSStringFromCGPoint(CGPoint rect);
876
877 MSInstanceMessage6(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode,letterSpacing,includeEmoji, CGPoint, point, CGFloat, width, UIFont *, font, UILineBreakMode, mode, CGFloat, spacing, BOOL, emoji) {
878 //NSLog(@"XXX: @\"%@\" %@ %g \"%@\" %u %g %u", self, NSStringFromCGPoint(point), width, font, mode, spacing, emoji);
879
880 WBStringDrawingState *state(stringDrawingState_);
881 if (state == NULL)
882 return MSOldCall(point, width, font, mode, spacing, emoji);
883
884 if (state->count_ != 0 && --state->count_ == 0)
885 stringDrawingState_ = state->next_;
886 if (state->info_ == nil)
887 return MSOldCall(point, width, font, mode, spacing, emoji);
888
889 NSString *info([Info_ objectForKey:state->info_]);
890 if (info == nil)
891 return MSOldCall(point, width, font, mode, spacing, emoji);
892
893 NSString *base(state->base_ ?: @"");
894 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
895 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
896 return CGSizeZero;
897 }
898
899 extern "C" NSString *NSStringFromCGRect(CGRect rect);
900
901 MSInstanceMessageHook7(CGSize, NSString, _drawInRect,withFont,lineBreakMode,alignment,lineSpacing,includeEmoji,truncationRect, CGRect, rect, UIFont *, font, UILineBreakMode, mode, UITextAlignment, alignment, float, spacing, BOOL, emoji, CGRect, truncation) {
902 //NSLog(@"XXX: @\"%@\" %@ \"%@\" %u %u %g %u %@", self, NSStringFromCGRect(rect), font, mode, alignment, spacing, emoji, NSStringFromCGRect(truncation));
903
904 WBStringDrawingState *state(stringDrawingState_);
905 if (state == NULL)
906 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
907
908 if (state->count_ != 0 && --state->count_ == 0)
909 stringDrawingState_ = state->next_;
910 if (state->info_ == nil)
911 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
912
913 NSString *info([Info_ objectForKey:state->info_]);
914 if (info == nil)
915 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
916
917 NSString *textAlign;
918 switch (alignment) {
919 default:
920 case UITextAlignmentLeft:
921 textAlign = @"left";
922 break;
923 case UITextAlignmentCenter:
924 textAlign = @"center";
925 break;
926 case UITextAlignmentRight:
927 textAlign = @"right";
928 break;
929 }
930
931 NSString *base(state->base_ ?: @"");
932 NSString *extra([NSString stringWithFormat:@"text-align: %@", textAlign]);
933
934 if (true)
935 $drawLabel$(self, rect, [NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], WBColorMarkup(), base], info);
936 else
937 [self drawInRect:rect withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
938
939 return CGSizeZero;
940 }
941
942 MSInstanceMessage2(void, NSString, drawInRect,withAttributes, CGRect, rect, NSDictionary *, attributes) {
943 //NSLog(@"XXX: *\"%@\" %@", self, attributes);
944
945 WBStringDrawingState *state(stringDrawingState_);
946 if (state == NULL)
947 return MSOldCall(rect, attributes);
948
949 if (state->count_ != 0 && --state->count_ == 0)
950 stringDrawingState_ = state->next_;
951 if (state->info_ == nil)
952 return MSOldCall(rect, attributes);
953
954 NSString *info([Info_ objectForKey:state->info_]);
955 if (info == nil)
956 return MSOldCall(rect, attributes);
957
958 NSString *base(state->base_ ?: @"");
959
960 UIFont *font([attributes objectForKey:@"NSFont"]);
961 UIColor *color([attributes objectForKey:@"NSColor"]);
962
963 [self drawInRect:rect withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(color), base, info]];
964 }
965
966 extern "C" NSString *NSStringFromCGSize(CGSize size);
967
968 MSInstanceMessage4(CGRect, NSString, boundingRectWithSize,options,attributes,context, CGSize, size, NSInteger, options, NSDictionary *, attributes, id, context) {
969 //NSLog(@"XXX: $\"%@\" %@ 0x%x %@ %@", self, NSStringFromCGSize(size), unsigned(options), attributes, context);
970
971 WBStringDrawingState *state(stringDrawingState_);
972 if (state == NULL)
973 return MSOldCall(size, options, attributes, context);
974
975 if (state->count_ != 0 && --state->count_ == 0)
976 stringDrawingState_ = state->next_;
977 if (state->info_ == nil)
978 return MSOldCall(size, options, attributes, context);
979
980 NSString *info([Info_ objectForKey:state->info_]);
981 if (info == nil)
982 return MSOldCall(size, options, attributes, context);
983
984 NSString *base(state->base_ ?: @"");
985
986 UIFont *font([attributes objectForKey:@"NSFont"]);
987 UIColor *color([attributes objectForKey:@"NSColor"]);
988
989 return (CGRect) {{0, 0}, [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(color), base, info] forWidth:size.width]};
990 }
991
992 MSInstanceMessage4(CGSize, NSString, sizeWithFont,forWidth,lineBreakMode,letterSpacing, UIFont *, font, CGFloat, width, UILineBreakMode, mode, CGFloat, spacing) {
993 //NSLog(@"XXX: #\"%@\" \"%@\" %g %u %g", self, font, width, mode, spacing);
994
995 WBStringDrawingState *state(stringDrawingState_);
996 if (state == NULL)
997 return MSOldCall(font, width, mode, spacing);
998
999 if (state->count_ != 0 && --state->count_ == 0)
1000 stringDrawingState_ = state->next_;
1001 if (state->info_ == nil)
1002 return MSOldCall(font, width, mode, spacing);
1003
1004 NSString *info([Info_ objectForKey:state->info_]);
1005 if (info == nil)
1006 return MSOldCall(font, width, mode, spacing);
1007
1008 NSString *base(state->base_ ?: @"");
1009 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
1010 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info] forWidth:width];
1011 }
1012
1013 MSInstanceMessage1(CGSize, NSString, sizeWithFont, UIFont *, font) {
1014 //NSLog(@"XXX: ?\"%@\"", self);
1015
1016 WBStringDrawingState *state(stringDrawingState_);
1017 if (state == NULL)
1018 return MSOldCall(font);
1019
1020 if (state->count_ != 0 && --state->count_ == 0)
1021 stringDrawingState_ = state->next_;
1022 if (state->info_ == nil)
1023 return MSOldCall(font);
1024
1025 NSString *info([Info_ objectForKey:state->info_]);
1026 if (info == nil)
1027 return MSOldCall(font);
1028
1029 NSString *base(state->base_ ?: @"");
1030 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), base, info] forWidth:65535];
1031 }
1032
1033 MSClassMessageHook2(id, SBIconBadgeView, checkoutAccessoryImagesForIcon,location, id, icon, int, location) {
1034 WBStringDrawingState badgeState = {NULL, 0, @""
1035 , @"BadgeStyle"};
1036
1037 stringDrawingState_ = &badgeState;
1038
1039 id images(MSOldCall(icon, location));
1040
1041 stringDrawingState_ = NULL;
1042 return images;
1043 }
1044
1045 MSClassMessageHook2(UIImage *, SBIconAccessoryImage, checkoutAccessoryImageForIcon,location, id, icon, int, location) {
1046 if ([self _imageClassForIcon:icon location:location] != $SBIconBadgeImage)
1047 return MSOldCall(icon, location);
1048
1049 WBStringDrawingState badgeState = {NULL, 0, @""
1050 , @"BadgeStyle"};
1051
1052 stringDrawingState_ = &badgeState;
1053
1054 UIImage *image(MSOldCall(icon, location));
1055
1056 stringDrawingState_ = NULL;
1057 return image;
1058 }
1059
1060 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
1061 WBStringDrawingState badgeState = {NULL, 0, @""
1062 , @"BadgeStyle"};
1063
1064 stringDrawingState_ = &badgeState;
1065
1066 UIImage *image(MSOldCall(text));
1067
1068 stringDrawingState_ = NULL;
1069 return image;
1070 }
1071
1072 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
1073 WBStringDrawingState dayState = {NULL, 2, @""
1074 // XXX: this is only correct on an iPod dock
1075 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
1076 , @"CalendarIconDayStyle"};
1077
1078 WBStringDrawingState skipState = {&dayState,
1079 unsigned(kCFCoreFoundationVersionNumber > 800 ? 16 : 7)
1080 , nil, nil};
1081
1082 WBStringDrawingState dateState = {&skipState, 2, @""
1083 , @"CalendarIconDateStyle"};
1084
1085 stringDrawingState_ = &dateState;
1086
1087 UIImage *image(MSOldCall(type));
1088
1089 stringDrawingState_ = NULL;
1090 return image;
1091 }
1092
1093 MSInstanceMessageHook1(UIImage *, UIStatusBarTimeItemView, contentsImageForStyle, int, style) {
1094 WBStringDrawingState timeState = {NULL, 0, @""
1095 , @"TimeStyle"};
1096
1097 stringDrawingState_ = &timeState;
1098
1099 UIImage *image(MSOldCall(style));
1100
1101 stringDrawingState_ = NULL;
1102 return image;
1103 }
1104
1105 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
1106 NSBundle *bundle([NSBundle mainBundle]);
1107
1108 CFLocaleRef locale(CFLocaleCopyCurrent());
1109 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
1110 CFRelease(locale);
1111
1112 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
1113
1114 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
1115 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
1116 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
1117 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
1118
1119 CFRelease(now);
1120
1121 CFRelease(formatter);
1122
1123 NSString *datestyle([@""
1124 "font-family: Helvetica; "
1125 "font-weight: bold; "
1126 "color: #333333; "
1127 "alpha: 1.0; "
1128 "" stringByAppendingString:(IsWild_
1129 ? @"font-size: 54px; "
1130 : @"font-size: 39px; "
1131 )]);
1132
1133 NSString *daystyle([@""
1134 "font-family: Helvetica; "
1135 "font-weight: bold; "
1136 "color: white; "
1137 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
1138 "" stringByAppendingString:(IsWild_
1139 ? @"font-size: 11px; "
1140 : @"font-size: 9px; "
1141 )]);
1142
1143 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
1144 datestyle = [datestyle stringByAppendingString:style];
1145 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
1146 daystyle = [daystyle stringByAppendingString:style];
1147
1148 CGFloat width([self bounds].size.width);
1149 float leeway(10);
1150 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
1151 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
1152
1153 unsigned base0(IsWild_ ? 89 : 70);
1154 if ($GSFontGetUseLegacyFontMetrics())
1155 base0 = base0 + 1;
1156 unsigned base1(IsWild_ ? 18 : 16);
1157
1158 if (Four_) {
1159 ++base0;
1160 ++base1;
1161 }
1162
1163 [(NSString *)date drawAtPoint:CGPointMake(
1164 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
1165 ) withStyle:datestyle];
1166
1167 [(NSString *)day drawAtPoint:CGPointMake(
1168 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
1169 ) withStyle:daystyle];
1170
1171 CFRelease(date);
1172 CFRelease(day);
1173 }
1174
1175 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
1176 void $setBarStyle$_(NSString *name, int &style) {
1177 if (Debug_)
1178 NSLog(@"WB:Debug:%@Style:%d", name, style);
1179 NSNumber *number = nil;
1180 if (number == nil)
1181 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
1182 if (number == nil)
1183 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
1184 if (number != nil) {
1185 style = [number intValue];
1186 if (Debug_)
1187 NSLog(@"WB:Debug:%@Style=%d", name, style);
1188 }
1189 }
1190
1191 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
1192 $setBarStyle$_(@"Toolbar", style);
1193 return MSOldCall(style);
1194 }
1195
1196 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
1197 $setBarStyle$_(@"NavigationBar", style);
1198 return MSOldCall(style);
1199 }
1200 // }}}
1201
1202 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
1203 [[self superview] setBackgroundColor:[UIColor clearColor]];
1204 _SBButtonBar$didMoveToSuperview(self, sel);
1205 }
1206
1207 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
1208 [[self superview] setBackgroundColor:[UIColor clearColor]];
1209 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
1210 }
1211
1212 static NSArray *Wallpapers_;
1213 static bool Papered_;
1214 static bool Docked_;
1215 static bool SMSBackgrounded_;
1216 static NSString *WallpaperFile_;
1217 static UIImageView *WallpaperImage_;
1218 static UIWebDocumentView *WallpaperPage_;
1219 static NSURL *WallpaperURL_;
1220
1221 #define _release(object) \
1222 do if (object != nil) { \
1223 [object release]; \
1224 object = nil; \
1225 } while (false)
1226
1227 static UIImage *$getImage$(NSString *path) {
1228 UIImage *image([UIImage imageWithContentsOfFile:path]);
1229
1230 unsigned scale($getScale$(path));
1231 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
1232 [image setScale:scale];
1233
1234 return image;
1235 }
1236
1237 template <typename Original_, typename Modified_>
1238 _finline UIImage *WBCacheImage(const Modified_ &modified, const Original_ &original, NSString *key) {
1239 UIImage *image([Images_ objectForKey:key]);
1240 if (image != nil)
1241 return reinterpret_cast<id>(image) == [NSNull null] ? original() : image;
1242 if (NSString *path = modified())
1243 image = $getImage$(path);
1244 [Images_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1245 return image == nil ? original() : image;
1246 }
1247
1248 static UIImage *$getDefaultDesktopImage$() {
1249 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
1250 return $getImage$(path);
1251 return nil;
1252 }
1253
1254 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
1255 return $getDefaultDesktopImage$() ?: MSOldCall();
1256 }
1257
1258 MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
1259 return $getDefaultDesktopImage$() ?: MSOldCall();
1260 }
1261
1262 MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
1263 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
1264 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
1265 if (UIImage *image = $getDefaultDesktopImage$()) {
1266 [self setImage:image];
1267 return;
1268 }
1269
1270 break;
1271 }
1272
1273 MSOldCall();
1274 }
1275
1276 // %hook -[SBUIController init] {{{
1277 MSInstanceMessageHook0(id, SBUIController, init) {
1278 self = MSOldCall();
1279 if (self == nil)
1280 return nil;
1281
1282 NSString *paper($getTheme$(Wallpapers_));
1283 if (paper != nil)
1284 paper = [paper stringByDeletingLastPathComponent];
1285
1286 if (Debug_)
1287 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
1288
1289 if (paper != nil) {
1290 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
1291 if (&_wallpaperView != NULL) {
1292 [_wallpaperView removeFromSuperview];
1293 [_wallpaperView release];
1294 _wallpaperView = nil;
1295 }
1296 }
1297
1298 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
1299 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
1300
1301 UIView **player;
1302 if (&_contentLayer != NULL)
1303 player = &_contentLayer;
1304 else if (&_contentView != NULL)
1305 player = &_contentView;
1306 else
1307 player = NULL;
1308 UIView *layer(player == NULL ? nil : *player);
1309
1310 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
1311 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
1312 [window setContentView:content];
1313
1314 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
1315 [window setBackgroundColor:[_window backgroundColor]];
1316 [_window setBackgroundColor:[UIColor clearColor]];
1317
1318 [window setLevel:-1000];
1319 [window setHidden:NO];
1320
1321 /*if (player != NULL)
1322 *player = content;*/
1323
1324 [content setBackgroundColor:[layer backgroundColor]];
1325 [layer setBackgroundColor:[UIColor clearColor]];
1326
1327 UIView *indirect;
1328 if (!SummerBoard_ || !IsWild_)
1329 indirect = content;
1330 else {
1331 CGRect bounds([content bounds]);
1332 bounds.origin.y = -30;
1333 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
1334 [content addSubview:indirect];
1335 [indirect zoomToScale:2.4];
1336 }
1337
1338 _release(WallpaperFile_);
1339 _release(WallpaperImage_);
1340 _release(WallpaperPage_);
1341 _release(WallpaperURL_);
1342
1343 if (paper != nil) {
1344 NSArray *themes([NSArray arrayWithObject:paper]);
1345
1346 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1347 #if UseAVController
1348 NSError *error;
1349
1350 static AVController *controller_(nil);
1351 if (controller_ == nil) {
1352 AVQueue *queue([AVQueue avQueue]);
1353 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1354 }
1355
1356 AVQueue *queue([controller_ queue]);
1357
1358 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1359 [controller_ setLayer:[video _layer]];
1360
1361 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1362 [queue appendItem:item error:&error];
1363
1364 [controller_ play:&error];
1365 #elif UseMPMoviePlayerController
1366 NSURL *url([NSURL fileURLWithPath:path]);
1367 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1368 controller.movieControlMode = MPMovieControlModeHidden;
1369 [controller play];
1370 #else
1371 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1372 [video setMovieWithPath:path];
1373 [video setRepeatMode:1];
1374 [video setRepeatGap:-1];
1375 [video playFromBeginning];;
1376 #endif
1377
1378 [indirect addSubview:video];
1379 }
1380
1381 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1382 if (UIImage *image = $getImage$(path)) {
1383 WallpaperFile_ = [path retain];
1384 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1385 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1386 [WallpaperImage_ setAlpha:[number floatValue]];
1387 [indirect addSubview:WallpaperImage_];
1388 }
1389 }
1390
1391 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1392 CGRect bounds = [indirect bounds];
1393
1394 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1395 [view setAutoresizes:true];
1396
1397 WallpaperPage_ = [view retain];
1398 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1399
1400 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1401
1402 [view setBackgroundColor:[UIColor clearColor]];
1403 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1404 [view setDrawsBackground:NO];
1405 [[view webView] setDrawsBackground:NO];
1406
1407 [indirect addSubview:view];
1408 }
1409 }
1410
1411 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1412 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1413 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1414 if ([Manager_ fileExistsAtPath:html]) {
1415 CGRect bounds = [indirect bounds];
1416
1417 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1418 [view setAutoresizes:true];
1419
1420 NSURL *url = [NSURL fileURLWithPath:html];
1421 [view loadRequest:[NSURLRequest requestWithURL:url]];
1422
1423 [view setBackgroundColor:[UIColor clearColor]];
1424 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1425 [view setDrawsBackground:NO];
1426 [[view webView] setDrawsBackground:NO];
1427
1428 [indirect addSubview:view];
1429 }
1430 }
1431
1432 return self;
1433 }
1434 // }}}
1435
1436 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1437 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1438 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1439
1440 if (path != nil && _backgroundView != nil)
1441 path = nil;
1442
1443 _SBAwayView$updateDesktopImage$(self, sel, image);
1444
1445 if (path != nil) {
1446 CGRect bounds = [self bounds];
1447
1448 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1449 [view setAutoresizes:true];
1450
1451 if (WallpaperPage_ != nil)
1452 [WallpaperPage_ release];
1453 WallpaperPage_ = [view retain];
1454
1455 if (WallpaperURL_ != nil)
1456 [WallpaperURL_ release];
1457 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1458
1459 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1460
1461 [[view webView] setDrawsBackground:false];
1462 [view setBackgroundColor:[UIColor clearColor]];
1463
1464 [self insertSubview:view aboveSubview:_backgroundView];
1465
1466 if ($objc_setAssociatedObject != NULL)
1467 $objc_setAssociatedObject(self, @selector(wb$widgetView), view, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1468 }
1469 }
1470
1471 MSHook(void, SBAwayView$_addSubview$positioned$relativeTo$, SBAwayView *self, SEL sel, UIView *view, int positioned, UIView *relative) {
1472 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1473 UIView *&_chargingView(MSHookIvar<UIView *>(self, "_chargingView"));
1474 if (&_chargingView != NULL)
1475 if (positioned == -2 && (relative == _backgroundView && _chargingView == nil || relative == _chargingView))
1476 if ($objc_getAssociatedObject != NULL)
1477 if (UIView *widget = $objc_getAssociatedObject(self, @selector(wb$widgetView)))
1478 relative = widget;
1479 return _SBAwayView$_addSubview$positioned$relativeTo$(self, sel, view, positioned, relative);
1480 }
1481
1482 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1483 extern "C" CGColorRef CGGStateGetFillColor(void *);
1484 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1485 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1486
1487 /* WBTimeLabel {{{ */
1488 @interface WBTimeLabel : NSProxy {
1489 NSString *time_;
1490 _transient SBStatusBarTimeView *view_;
1491 }
1492
1493 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1494
1495 @end
1496
1497 @implementation WBTimeLabel
1498
1499 - (void) dealloc {
1500 [time_ release];
1501 [super dealloc];
1502 }
1503
1504 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1505 time_ = [time retain];
1506 view_ = view;
1507 return self;
1508 }
1509
1510 - (NSString *) description {
1511 return time_;
1512 }
1513
1514 WBDelegate(time_)
1515
1516 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1517 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1518 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1519
1520 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1521 "font-family: Helvetica; "
1522 "font-weight: bold; "
1523 "font-size: 14px; "
1524 "color: %@; "
1525 "%@", _mode ? @"white" : @"black", custom]];
1526
1527 return CGSizeZero;
1528 }
1529
1530 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1531 }
1532
1533 @end
1534 /* }}} */
1535 /* WBBadgeLabel {{{ */
1536 @interface WBBadgeLabel : NSProxy {
1537 NSString *badge_;
1538 }
1539
1540 - (id) initWithBadge:(NSString *)badge;
1541 - (NSString *) description;
1542
1543 @end
1544
1545 @implementation WBBadgeLabel
1546
1547 - (void) dealloc {
1548 [badge_ release];
1549 [super dealloc];
1550 }
1551
1552 - (id) initWithBadge:(NSString *)badge {
1553 badge_ = [badge retain];
1554 return self;
1555 }
1556
1557 - (NSString *) description {
1558 return [badge_ description];
1559 }
1560
1561 WBDelegate(badge_)
1562
1563 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1564 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1565 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1566 "font-family: Helvetica; "
1567 "font-weight: bold; "
1568 "font-size: 17px; "
1569 "color: white; "
1570 "%@", custom]];
1571
1572 return CGSizeZero;
1573 }
1574
1575 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1576 }
1577
1578 @end
1579 /* }}} */
1580
1581 // IconAlpha {{{
1582 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, CGFloat, alpha) {
1583 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1584 alpha = [number floatValue];
1585 return MSOldCall(alpha);
1586 }
1587
1588 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, CGFloat, alpha) {
1589 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1590 alpha = [number floatValue];
1591 return MSOldCall(alpha);
1592 }
1593
1594 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1595 if ((self = MSOldCall()) != nil) {
1596 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1597 // XXX: note: this is overridden above, which is silly
1598 float alpha([number floatValue]);
1599 if ([self respondsToSelector:@selector(setIconImageAlpha:)])
1600 [self setIconImageAlpha:alpha];
1601 if ([self respondsToSelector:@selector(setIconLabelAlpha:)])
1602 [self setIconLabelAlpha:alpha];
1603 if ([self respondsToSelector:@selector(setAlpha:)])
1604 [self setAlpha:alpha];
1605 }
1606 } return self;
1607 }
1608
1609 MSInstanceMessageHook1(void, SBIcon, setAlpha, CGFloat, alpha) {
1610 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1611 alpha = [number floatValue];
1612 return MSOldCall(alpha);
1613 }
1614 // }}}
1615
1616 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1617 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1618 id &_badge(MSHookIvar<id>(self, "_badge"));
1619 if (_badge != nil)
1620 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1621 _badge = label;
1622 } return self;
1623 }
1624
1625 void SBStatusBarController$setStatusBarMode(int &mode) {
1626 if (Debug_)
1627 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1628 if (mode < 100) // 104:hidden 105:glowing
1629 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1630 mode = [number intValue];
1631 }
1632
1633 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1634 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1635 SBStatusBarController$setStatusBarMode(mode);
1636 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1637 }*/
1638
1639 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1640 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1641 SBStatusBarController$setStatusBarMode(mode);
1642 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1643 }
1644
1645 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) {
1646 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1647 SBStatusBarController$setStatusBarMode(mode);
1648 //NSLog(@"mode=%u", mode);
1649 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1650 }
1651
1652 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1653 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1654 mode = [number intValue];
1655 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1656 }*/
1657
1658 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1659 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1660 if (Debug_)
1661 NSLog(@"operatorNameStyle= %@", style);
1662 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1663 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1664 return style;
1665 }
1666
1667 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1668 if (Debug_)
1669 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1670 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1671 }
1672
1673 // XXX: replace this with [SBStatusBarTimeView tile]
1674 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1675 id &_time(MSHookIvar<id>(self, "_time"));
1676 if (_time != nil && [_time class] != [WBTimeLabel class])
1677 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1678 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1679 }
1680
1681 @interface UIView (WinterBoard)
1682 - (bool) wb$isWBImageView;
1683 - (void) wb$logHierarchy;
1684 - (void) wb$setBackgroundColor:(UIColor *)color;
1685 @end
1686
1687 @implementation UIView (WinterBoard)
1688
1689 - (bool) wb$isWBImageView {
1690 return false;
1691 }
1692
1693 - (void) wb$logHierarchy {
1694 WBLogHierarchy(self);
1695 }
1696
1697 - (void) wb$setBackgroundColor:(UIColor *)color {
1698 [self setBackgroundColor:color];
1699 for (UIView *child in [self subviews])
1700 [child wb$setBackgroundColor:color];
1701 }
1702
1703 @end
1704
1705 @interface WBImageView : UIImageView {
1706 }
1707
1708 - (bool) wb$isWBImageView;
1709 - (void) wb$updateFrame;
1710 @end
1711
1712 @implementation WBImageView
1713
1714 - (bool) wb$isWBImageView {
1715 return true;
1716 }
1717
1718 - (void) wb$updateFrame {
1719 CGRect frame([self frame]);
1720 frame.origin.y = 0;
1721
1722 for (UIView *view(self); ; ) {
1723 view = [view superview];
1724 if (view == nil)
1725 break;
1726 frame.origin.y -= [view frame].origin.y;
1727 }
1728
1729 [self setFrame:frame];
1730 }
1731
1732 @end
1733
1734 static void SBIconList$updateFrames$(SBIconList *self) {
1735 NSArray *subviews([self subviews]);
1736 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1737 if (view != nil && [view wb$isWBImageView])
1738 [view wb$updateFrame];
1739 }
1740
1741 MSHook(void, SBIconList$didMoveToSuperview, SBIconList *self, SEL sel) {
1742 SBIconList$updateFrames$(self);
1743 _SBIconList$didMoveToSuperview(self, sel);
1744 }
1745
1746 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1747 SBIconList$updateFrames$(self);
1748 _SBIconList$setFrame$(self, sel, frame);
1749 }
1750
1751 static void $addPerPageView$(unsigned i, UIView *list) {
1752 NSString *path($getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]]));
1753 if (path == nil)
1754 return;
1755
1756 NSArray *subviews([list subviews]);
1757
1758 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1759 if (view == nil || ![view wb$isWBImageView]) {
1760 view = [[[WBImageView alloc] init] autorelease];
1761 [list insertSubview:view atIndex:0];
1762 }
1763
1764 UIImage *image([UIImage imageWithContentsOfFile:path]);
1765
1766 CGRect frame([view frame]);
1767 frame.size = [image size];
1768 [view setFrame:frame];
1769
1770 [view setImage:image];
1771 [view wb$updateFrame];
1772 }
1773
1774 static void $addPerPageViews$(NSArray *lists) {
1775 for (unsigned i(0), e([lists count]); i != e; ++i)
1776 $addPerPageView$(i, [lists objectAtIndex:i]);
1777 }
1778
1779 MSInstanceMessageHook0(void, SBIconController, updateNumberOfRootIconLists) {
1780 NSArray *&_rootIconLists(MSHookIvar<NSArray *>(self, "_rootIconLists"));
1781 $addPerPageViews$(_rootIconLists);
1782 return MSOldCall();
1783 }
1784
1785 MSInstanceMessageHook0(void, SBIconContentView, layoutSubviews) {
1786 MSOldCall();
1787
1788 if (SBIconController *controller = [$SBIconController sharedInstance]) {
1789 UIView *&_dockContainerView(MSHookIvar<UIView *>(controller, "_dockContainerView"));
1790 if (&_dockContainerView != NULL)
1791 [[_dockContainerView superview] bringSubviewToFront:_dockContainerView];
1792 }
1793 }
1794
1795 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1796 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1797 $addPerPageViews$([_iconModel iconLists]);
1798 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1799 }
1800
1801 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1802 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1803 if (self != nil)
1804 [self setClipsToBounds:NO];
1805 return self;
1806 }
1807
1808 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1809 static bool gssc(false);
1810 if (!gssc) {
1811 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1812 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1813 gssc = true;
1814
1815 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1816 [Info_ setObject:[NSNumber numberWithBool:(
1817 !Papered_ ||
1818 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1819 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1820 )] forKey:@"UndockedIconLabels"];
1821 }
1822
1823 id &_label(MSHookIvar<id>(self, "_label"));
1824 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1825 docked = true;
1826
1827 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1828 [_label setInDock:docked];
1829
1830 _SBIconLabel$setInDock$(self, sel, docked);
1831 [self setNeedsDisplay];
1832 }
1833
1834 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1835 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1836 }
1837
1838 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1839 _SBDockIconListView$setFrame$(self, sel, frame);
1840 }
1841
1842 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1843 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1844 NSString *identifier = [self bundleIdentifier];
1845 NSLocale *locale = [NSLocale currentLocale];
1846 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1847 if (Debug_)
1848 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1849 NSString *file = table == nil ? @"Localizable" : table;
1850 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1851 NSDictionary *strings;
1852 if ((strings = [Strings_ objectForKey:name]) != nil) {
1853 if (static_cast<id>(strings) != [NSNull null]) strings:
1854 if (NSString *value = [strings objectForKey:key])
1855 return value;
1856 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1857 language, file
1858 ], self, false)) {
1859 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1860 [Strings_ setObject:[strings autorelease] forKey:name];
1861 goto strings;
1862 } else goto null;
1863 } else null:
1864 [Strings_ setObject:[NSNull null] forKey:name];
1865 return MSOldCall(key, value, table);
1866 }
1867 // }}}
1868 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1869 MSClassHook(WebCoreFrameBridge)
1870
1871 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1872 if (node == nil)
1873 return CGSizeZero;
1874 void **core(reinterpret_cast<void **>([node _node]));
1875 if (core == NULL || core[6] == NULL)
1876 return CGSizeZero;
1877 return MSOldCall(node, width);
1878 }
1879 // }}}
1880
1881 MSInstanceMessage1(void, SBIconLabel, drawRect, CGRect, rect) {
1882 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1883
1884 int docked;
1885 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1886 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1887
1888 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1889
1890 NSString *style = [NSString stringWithFormat:@""
1891 "font-family: Helvetica; "
1892 "font-weight: bold; "
1893 "color: %@; %@"
1894 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1895 ? @"font-size: 12px; "
1896 : @"font-size: 11px; "
1897 )];
1898
1899 if (IsWild_)
1900 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1901 else if (docked)
1902 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1903
1904 NSString *custom([Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")]);
1905
1906 $drawLabel$(label, [self bounds], style, custom);
1907 }
1908
1909 MSInstanceMessage0(CGImageRef, SBIconLabel, buildLabelImage) {
1910 bool docked((MSHookIvar<unsigned>(self, "_inDock") & 0x2) != 0);
1911
1912 WBStringDrawingState labelState = {NULL, 0, @""
1913 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1914
1915 stringDrawingState_ = &labelState;
1916
1917 //NSLog(@"XXX: +");
1918 CGImageRef image(MSOldCall());
1919 //NSLog(@"XXX: -");
1920
1921 stringDrawingState_ = NULL;
1922 return image;
1923 }
1924
1925 static bool wb$inDock(id parameters) {
1926 return [$objc_getAssociatedObject(parameters, @selector(wb$inDock)) boolValue];
1927 }
1928
1929 MSInstanceMessage0(NSUInteger, SBIconLabelImageParameters, hash) {
1930 return MSOldCall() + (wb$inDock(self) ? 0xdeadbeef : 0xd15ea5e);
1931 }
1932
1933 MSClassMessage2(id, SBIconView, _labelImageParametersForIcon,location, id, icon, int, location) {
1934 if (id parameters = MSOldCall(icon, location)) {
1935 $objc_setAssociatedObject(parameters, @selector(wb$inDock), [NSNumber numberWithBool:(location == 1)], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1936 return parameters;
1937 } return nil;
1938 }
1939
1940 MSInstanceMessage0(id, SBIconView, _labelImageParameters) {
1941 if (id parameters = MSOldCall()) {
1942 int &location(MSHookIvar<int>(self, "_iconLocation"));
1943 if (&location != NULL)
1944 $objc_setAssociatedObject(parameters, @selector(wb$inDock), [NSNumber numberWithBool:(location == 3)], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1945 return parameters;
1946 } return nil;
1947 }
1948
1949 MSClassMessage1(UIImage *, SBIconLabelImage, _drawLabelImageForParameters, id, parameters) {
1950 bool docked(wb$inDock(parameters));
1951
1952 WBStringDrawingState labelState = {NULL, 0, @""
1953 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1954
1955 stringDrawingState_ = &labelState;
1956
1957 //NSLog(@"XXX: +");
1958 UIImage *image(MSOldCall(parameters));
1959 //NSLog(@"XXX: -");
1960
1961 stringDrawingState_ = NULL;
1962 return image;
1963 }
1964
1965 // ChatKit {{{
1966 MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1967 if ((self = MSOldCall(frame, delegate)) != nil) {
1968 [self setBackgroundColor:[UIColor clearColor]];
1969 } return self;
1970 }
1971
1972 MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1973 return SMSBackgrounded_ ? NO : MSOldCall();
1974 }
1975
1976 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1977 [self wb$setBackgroundColor:[UIColor clearColor]];
1978 return MSOldCall();
1979 }
1980
1981 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1982 MSOldCall(balloon);
1983 [balloon setBackgroundColor:[UIColor clearColor]];
1984 }
1985
1986 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1987 MSOldCall([UIColor clearColor]);
1988 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1989 }
1990
1991 // iOS >= 5.0
1992 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1993 if ((self = MSOldCall(style, reuse)) != nil) {
1994 [self setBackgroundColor:[UIColor clearColor]];
1995 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1996 } return self;
1997 }
1998
1999 // iOS << 5.0
2000 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
2001 if ((self = MSOldCall(style, reuse)) != nil) {
2002 [self setBackgroundColor:[UIColor clearColor]];
2003 [[self contentView] setBackgroundColor:[UIColor clearColor]];
2004 } return self;
2005 }
2006
2007 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
2008 if ((self = MSOldCall(style, reuse)) != nil) {
2009 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
2010 [_label setBackgroundColor:[UIColor clearColor]];
2011 } return self;
2012 }
2013
2014 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
2015 MSOldCall(UITableViewCellSeparatorStyleNone);
2016 }
2017
2018 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
2019 if ((self = MSOldCall(frame, style)) != nil) {
2020 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
2021 } return self;
2022 }
2023
2024 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
2025 MSOldCall();
2026
2027 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
2028 if (UIImage *image = $getImage$(path)) {
2029 SMSBackgrounded_ = true;
2030
2031 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
2032 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
2033 UIView *table;
2034 if (&_transcriptTable != NULL)
2035 table = _transcriptTable;
2036 else if (&_transcriptLayer != NULL)
2037 table = _transcriptLayer;
2038 else
2039 table = nil;
2040
2041 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
2042 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
2043
2044 if (table == nil)
2045 [placard insertSubview:background atIndex:0];
2046 else {
2047 [table setBackgroundColor:[UIColor clearColor]];
2048 [placard insertSubview:background belowSubview:table];
2049 }
2050 }
2051 }
2052 // }}}
2053
2054 template <typename Original_>
2055 static UIImage *WBCacheImage(NSBundle *bundle, NSString *name, const Original_ &original, NSString *key) {
2056 if (name == nil)
2057 return original();
2058 NSUInteger period([name rangeOfString:@"."].location);
2059 NSUInteger length([name length]);
2060 if (period == NSNotFound || length < 4 || period > length - 4)
2061 name = [name stringByAppendingString:@".png"];
2062
2063 return WBCacheImage(
2064 [=](){ return $pathForFile$inBundle$(name, bundle, true); },
2065 [bundle, &original, name](){
2066 UIImage *image(original());
2067 if (image != nil && UIDebug_) {
2068 NSString *path([@"/tmp/WBImages/" stringByAppendingString:[bundle bundleIdentifier]]);
2069 [Manager_ createDirectoryAtPath:path withIntermediateDirectories:YES attributes:@{NSFilePosixPermissions: @0777} error:NULL];
2070 path = [NSString stringWithFormat:@"%@/%@", path, name];
2071 if (![Manager_ fileExistsAtPath:path])
2072 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
2073 } return image;
2074 },
2075 key);
2076 }
2077
2078 // %hook _UIImageWithName() {{{
2079 MSHook(UIImage *, _UIImageWithName, NSString *name) {
2080 if (name == nil)
2081 return nil;
2082 if (Debug_)
2083 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
2084 return WBCacheImage(_UIKitBundle(), name,
2085 [=](){ return __UIImageWithName(name); },
2086 [NSString stringWithFormat:@"I:%@", name]);
2087 }
2088 // }}}
2089 // %hook _UIImageWithNameInDomain() {{{
2090 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
2091 if (Debug_)
2092 NSLog(@"WB:Debug: _UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
2093 return WBCacheImage(
2094 [=](){ return $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])); },
2095 [=](){ return __UIImageWithNameInDomain(name, domain); },
2096 [NSString stringWithFormat:@"D:%zu:%@%@", size_t([domain length]), domain, name]);
2097 }
2098 // }}}
2099
2100 // UISharedArtwork (iOS 6) {{{
2101 MSInstanceMessageHook2(UISharedArtwork *, UISharedArtwork, initWithName,inBundle, NSString *, name, NSBundle *, bundle) {
2102 if ((self = MSOldCall(name, bundle)) != nil) {
2103 $objc_setAssociatedObject(self, @selector(wb$bundle), bundle, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
2104 } return self;
2105 }
2106
2107 MSInstanceMessageHook2(UIImage *, UISharedArtwork, imageNamed,device, NSString *, name, NSInteger, device) {
2108 NSBundle *bundle($objc_getAssociatedObject(self, @selector(wb$bundle)));
2109 if (Debug_)
2110 NSLog(@"WB:Debug: -[UISharedArtwork(%@) imageNamed:@\"%@\" device:%li]", [bundle bundleIdentifier], name, (long) device);
2111 return WBCacheImage(bundle, name,
2112 [=](){ return MSOldCall(name, device); },
2113 [NSString stringWithFormat:@"M:%p:%@:%li", self, name, (long) device]);
2114 }
2115 // }}}
2116 // _UIAssetManager (iOS 7) {{{
2117 MSInstanceMessageHook3(_UIAssetManager *, _UIAssetManager, initWithName,inBundle,idiom, NSString *, name, NSBundle *, bundle, NSInteger, idiom) {
2118 if ((self = MSOldCall(name, bundle, idiom)) != nil) {
2119 $objc_setAssociatedObject(self, @selector(wb$bundle), bundle, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
2120 } return self;
2121 }
2122
2123 MSInstanceMessageHook5(UIImage *, _UIAssetManager, imageNamed,scale,idiom,subtype,cachingOptions, NSString *, name, CGFloat, scale, NSInteger, idiom, NSUInteger, subtype, NSUInteger, caching) {
2124 NSBundle *bundle($objc_getAssociatedObject(self, @selector(wb$bundle)));
2125 if (Debug_)
2126 NSLog(@"WB:Debug: -[_UIAssetManager(%@/%@) imageNamed:@\"%@\" scale:%g idiom:%li subtype:%lu cachingOptions:%lu]",
2127 [bundle bundleIdentifier], [self carFileName],
2128 name, scale, (long) idiom,
2129 (unsigned long) subtype,
2130 (unsigned long) caching
2131 );
2132
2133 if (bundle == _UIKitBundle()) {
2134 NSString *name([self carFileName]);
2135 if (false);
2136 else if ([name isEqualToString:@"UIKit_NewArtwork"])
2137 bundle = [WBBundle bundleWithIdentifier:@"com.apple.uikit.Artwork"];
2138 else if ([name isEqualToString:@"UIKit_OriginalArtwork"])
2139 bundle = [WBBundle bundleWithIdentifier:@"com.apple.uikit.LegacyArtwork"];
2140 }
2141
2142 return WBCacheImage(bundle, name,
2143 [=](){ return MSOldCall(name, scale, idiom, subtype, caching); },
2144 [NSString stringWithFormat:@"M:%p:%@:%g:%li:%lu", self, name, scale, (long) idiom, (unsigned long) subtype]);
2145 }
2146 // }}}
2147 // _UIAssetManager (iOS 8) {{{
2148 struct SizeClassPair {
2149 NSInteger first;
2150 NSInteger second;
2151 };
2152
2153 MSInstanceMessageHook7(UIImage *, _UIAssetManager, imageNamed,scale,idiom,subtype,cachingOptions,sizeClassPair,attachCatalogImage, NSString *, name, CGFloat, scale, NSInteger, idiom, NSUInteger, subtype, NSUInteger, caching, SizeClassPair, size, BOOL, attach) {
2154 NSBundle *bundle([self bundle]);
2155 if (Debug_)
2156 NSLog(@"WB:Debug: -[_UIAssetManager(%@/%@) imageNamed:@\"%@\" scale:%g idiom:%li subtype:%lu cachingOptions:%lu sizeClassPair:[%li %li] attachCatalogImage:%s]",
2157 [bundle bundleIdentifier], [self carFileName],
2158 name, scale, (long) idiom,
2159 (unsigned long) subtype,
2160 (unsigned long) caching,
2161 (long) size.first, (long) size.second,
2162 attach ? "YES" : "NO"
2163 );
2164 return WBCacheImage(bundle, name,
2165 [=](){ return MSOldCall(name, scale, idiom, subtype, caching, size, attach); },
2166 [NSString stringWithFormat:@"M:%p:%@:%g:%li:%lu:%li:%li:%c", self, name, scale, (long) idiom, (unsigned long) subtype, (long) size.first, (long) size.second, attach ? 'Y' : 'N']);
2167 }
2168 // }}}
2169
2170 // %hook GSFontCreateWithName() {{{
2171 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
2172 if (Debug_)
2173 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
2174 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
2175 name = [font UTF8String];
2176 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
2177 // size *= [scale floatValue];
2178 return _GSFontCreateWithName(name, traits, size);
2179 }
2180 // }}}
2181
2182 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
2183
2184 static bool GetFileNameForThisAction$(bool value, unsigned long a0, char *a1, unsigned long a2, bool &a3) {
2185 if (Debug_)
2186 NSLog(@"WB:Debug:GetFileNameForThisAction(%lu, %s, %lu, %u) = %u", a0, value ? a1 : NULL, a2, a3, value);
2187
2188 if (value) {
2189 NSString *path = [NSString stringWithUTF8String:a1];
2190 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
2191 NSString *file = [path substringFromIndex:31];
2192 for (NSString *theme in Themes_) {
2193 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
2194 if ([Manager_ fileExistsAtPath:path]) {
2195 strcpy(a1, [path UTF8String]);
2196 break;
2197 }
2198 }
2199 }
2200 }
2201 return value;
2202 }
2203
2204 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a3) {
2205 bool value(__Z24GetFileNameForThisActionmPcRb(a0, a1, a3));
2206 return GetFileNameForThisAction$(value, a0, a1, 0, a3);
2207 }
2208
2209 #ifdef __LP64__
2210 MSHook(bool, _Z24GetFileNameForThisActionjPcjRb, unsigned int a0, char *a1, unsigned int a2, bool &a3) {
2211 bool value(__Z24GetFileNameForThisActionjPcjRb(a0, a1, a2, a3));
2212 return GetFileNameForThisAction$(value, a0, a1, a2, a3);
2213 }
2214 #else
2215 MSHook(bool, _Z24GetFileNameForThisActionmPcmRb, unsigned long a0, char *a1, unsigned long a2, bool &a3) {
2216 bool value(__Z24GetFileNameForThisActionmPcmRb(a0, a1, a2, a3));
2217 return GetFileNameForThisAction$(value, a0, a1, a2, a3);
2218 }
2219 #endif
2220
2221 static void ChangeWallpaper(
2222 CFNotificationCenterRef center,
2223 void *observer,
2224 CFStringRef name,
2225 const void *object,
2226 CFDictionaryRef info
2227 ) {
2228 if (Debug_)
2229 NSLog(@"WB:Debug:ChangeWallpaper!");
2230
2231 UIImage *image;
2232 if (WallpaperFile_ != nil) {
2233 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
2234 if (image != nil)
2235 image = [image autorelease];
2236 } else image = nil;
2237
2238 if (WallpaperImage_ != nil)
2239 [WallpaperImage_ setImage:image];
2240 if (WallpaperPage_ != nil)
2241 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
2242
2243 }
2244
2245 MSHook(NSArray *, CPBitmapCreateImagesFromPath, NSString *path, CFTypeRef *names, void *arg2, void *arg3) {
2246 NSArray *images(_CPBitmapCreateImagesFromPath(path, names, arg2, arg3));
2247 if (images == nil)
2248 return nil;
2249 if (*names == nil)
2250 return images;
2251
2252 NSBundle *bundle([NSBundle wb$bundleWithFile:path]);
2253 if (bundle == nil)
2254 return images;
2255
2256 NSString *file([path stringByResolvingSymlinksInPath]);
2257 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
2258 // XXX: why do I care about this?
2259 if (![file hasPrefix:prefix])
2260 return images;
2261
2262 NSMutableArray *copy([images mutableCopy]);
2263 [images release];
2264 images = copy;
2265
2266 NSDictionary *indexes;
2267 NSEnumerator *enumerator;
2268
2269 if (CFGetTypeID((CFTypeRef) *names) == CFDictionaryGetTypeID()) {
2270 indexes = (NSDictionary *) *names;
2271 enumerator = [indexes keyEnumerator];
2272 } else {
2273 indexes = nil;
2274 enumerator = [(NSArray *) *names objectEnumerator];
2275 }
2276
2277 for (NSUInteger index(0); NSString *name = [enumerator nextObject]; ++index)
2278 if (NSString *themed = $pathForFile$inBundle$([name stringByAppendingString:@".png"], bundle, true)) {
2279 if (indexes != nil)
2280 index = [[indexes objectForKey:name] intValue];
2281 if (UIImage *image = $getImage$(themed))
2282 [copy replaceObjectAtIndex:index withObject:(id)[image CGImage]];
2283 }
2284
2285 return images;
2286 }
2287
2288 MSHook(void, BKSDisplayServicesSetSystemAppExitedImagePath, NSString *path) {
2289 if (NSString *themed = $getTheme$($useScale$([NSArray arrayWithObject:@"SystemAppExited.png"])))
2290 path = themed;
2291 _BKSDisplayServicesSetSystemAppExitedImagePath(path);
2292 }
2293
2294 #define WBRename(name, sel, imp) \
2295 MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp, &_ ## name ## $ ## imp)
2296
2297 template <typename Type_>
2298 static void msset(Type_ &function, MSImageRef image, const char *name) {
2299 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
2300 }
2301
2302 #define WBHookSymbol(image, function) \
2303 msset(function, image, "_" #function)
2304
2305 template <typename Type_>
2306 static void dlset(Type_ &function, const char *name) {
2307 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
2308 }
2309
2310 // %hook CGImageReadCreateWithFile() {{{
2311 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
2312 if (Debug_)
2313 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
2314 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2315 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
2316 [pool release];
2317 return value;
2318 }
2319
2320 MSHook(void *, CGImageSourceCreateWithFile, NSString *path, NSDictionary *options) {
2321 if (Debug_)
2322 NSLog(@"WB:Debug: CGImageSourceCreateWithFile(%@, %@)", path, options);
2323 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2324 void *value(_CGImageSourceCreateWithFile([path wb$themedPath], options));
2325 [pool release];
2326 return value;
2327 }
2328
2329 MSHook(void *, CGImageSourceCreateWithURL, NSURL *url, NSDictionary *options) {
2330 if (Debug_)
2331 NSLog(@"WB:Debug: CGImageSourceCreateWithURL(%@, %@)", url, options);
2332 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2333 if ([url isFileURL])
2334 url = [NSURL fileURLWithPath:[[url path] wb$themedPath]];
2335 void *value(_CGImageSourceCreateWithURL(url, options));
2336 [pool release];
2337 return value;
2338 }
2339 // }}}
2340
2341 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
2342 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
2343 if (style == nil || [style length] == 0)
2344 style = @"font-family: Helvetica; font-size: 12px";
2345 //NSLog(@"XXX:drawP(%@ | %@)", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
2346 [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
2347 }
2348
2349 static void NSString$drawInRect$withStyle$(NSString *self, SEL _cmd, CGRect rect, NSString *style) {
2350 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
2351 if (style == nil || [style length] == 0)
2352 style = @"font-family: Helvetica; font-size: 12px";
2353 //NSLog(@"XXX:drawR(%@ | %@)", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
2354 return [[WBMarkup sharedMarkup] drawString:self inRect:rect withStyle:style];
2355 }
2356
2357 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, CGFloat width) {
2358 if (style == nil || [style length] == 0)
2359 style = @"font-family: Helvetica; font-size: 12px";
2360 CGSize size([[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width]);
2361 //NSLog(@"XXX:size(%@ | %@) = [%g %g]", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "], size.width, size.height);
2362 return size;
2363 }
2364
2365 static void SBInitialize() {
2366 if (SummerBoard_) {
2367 WBRename(SBApplication, pathForIcon, pathForIcon);
2368 WBRename(SBApplicationIcon, icon, icon);
2369 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
2370 }
2371
2372 WBRename(SBBookmarkIcon, icon, icon);
2373 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
2374 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
2375 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
2376 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
2377
2378 WBRename(SBWidgetApplicationIcon, icon, icon);
2379
2380 WBRename(SBDockIconListView, setFrame:, setFrame$);
2381 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
2382
2383 if (kCFCoreFoundationVersionNumber < 600 || SummerBoard_)
2384 WBRename(SBIconLabel, drawRect:, drawRect$);
2385 else if (kCFCoreFoundationVersionNumber < 700) {
2386 WBRename(SBIconLabel, buildLabelImage, buildLabelImage);
2387 } else {
2388 WBRename(SBIconLabelImageParameters, hash, hash);
2389 WBRename($SBIconView, _labelImageParametersForIcon:location:, _labelImageParametersForIcon$location$);
2390 WBRename(SBIconView, _labelImageParameters, _labelImageParameters);
2391 WBRename($SBIconLabelImage, _drawLabelImageForParameters:, _drawLabelImageForParameters$);
2392 }
2393
2394 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
2395 WBRename(SBIconLabel, setInDock:, setInDock$);
2396
2397 WBRename(SBIconList, didMoveToSuperview, didMoveToSuperview);
2398 WBRename(SBIconList, setFrame:, setFrame$);
2399
2400 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
2401 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
2402 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
2403 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
2404
2405 if (kCFCoreFoundationVersionNumber < 800) {
2406 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
2407 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
2408 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
2409 }
2410
2411 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
2412
2413 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
2414 if (kCFCoreFoundationVersionNumber >= 700)
2415 WBRename(SBAwayView, _addSubview:positioned:relativeTo:, _addSubview$positioned$relativeTo$);
2416
2417 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
2418 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
2419 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
2420 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
2421 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
2422 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
2423 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
2424 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
2425
2426 if (SummerBoard_)
2427 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
2428
2429 if (kCFCoreFoundationVersionNumber >= 800) {
2430 WBRename(NSString, drawInRect:withAttributes:, drawInRect$withAttributes$);
2431 WBRename(NSString, boundingRectWithSize:options:attributes:context:, boundingRectWithSize$options$attributes$context$);
2432 }
2433 }
2434
2435 /*MSHook(int, open, const char *path, int oflag, mode_t mode) {
2436 int fd(_open(path, oflag, mode));
2437
2438 static bool no(false);
2439 if (no) return fd;
2440 no = true;
2441
2442 if (strstr(path, "/icon") != NULL)
2443 *reinterpret_cast<void *volatile *>(NULL) = NULL;
2444
2445 if (fd == -1 && errno == EFAULT)
2446 NSLog(@"open(%p, %#x, %#o) = %d\n", path, oflag, mode, fd);
2447 else
2448 NSLog(@"open(\"%s\", %#x, %#o) = %d\n", path, oflag, mode, fd);
2449
2450 no = false;
2451 return fd;
2452 }*/
2453
2454 MSInitialize {
2455 $objc_setAssociatedObject = reinterpret_cast<void (*)(id, void *, id value, objc_AssociationPolicy)>(dlsym(RTLD_DEFAULT, "objc_setAssociatedObject"));
2456 $objc_getAssociatedObject = reinterpret_cast<id (*)(id, void *)>(dlsym(RTLD_DEFAULT, "objc_getAssociatedObject"));
2457 $objc_removeAssociatedObjects = reinterpret_cast<void (*)(id)>(dlsym(RTLD_DEFAULT, "objc_removeAssociatedObjects"));
2458
2459 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2460
2461 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
2462 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
2463
2464 Manager_ = [[NSFileManager defaultManager] retain];
2465 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
2466
2467 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
2468
2469 // Initialize IsWild_ {{{
2470 size_t size;
2471 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
2472 char *machine = new char[size];
2473
2474 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
2475 perror("sysctlbyname(\"hw.machine\", ?)");
2476 delete [] machine;
2477 machine = NULL;
2478 }
2479
2480 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
2481 // }}}
2482 // Load Settings.plist {{{
2483 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
2484 if (kCFCoreFoundationVersionNumber >= 1000)
2485 SummerBoard_ = false;
2486 else if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
2487 SummerBoard_ = [value boolValue];
2488 else
2489 SummerBoard_ = true;
2490
2491 if (NSNumber *value = [settings objectForKey:@"Debug"])
2492 Debug_ = [value boolValue];
2493 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
2494 UIDebug_ = [value boolValue];
2495
2496 NSArray *themes([settings objectForKey:@"Themes"]);
2497 if (themes == nil)
2498 if (NSString *theme = [settings objectForKey:@"Theme"])
2499 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
2500 theme, @"Name",
2501 [NSNumber numberWithBool:true], @"Active",
2502 nil]];
2503
2504 if (themes != nil)
2505 for (NSDictionary *theme in themes) {
2506 NSNumber *active([theme objectForKey:@"Active"]);
2507 if (![active boolValue])
2508 continue;
2509
2510 NSString *name([theme objectForKey:@"Name"]);
2511 if (name == nil)
2512 continue;
2513
2514 #define testForTheme(format...) \
2515 { \
2516 NSString *path = [NSString stringWithFormat:format]; \
2517 if ([Manager_ fileExistsAtPath:path]) { \
2518 [Themes_ addObject:path]; \
2519 continue; \
2520 } \
2521 }
2522
2523 testForTheme(@"/Library/Themes/%@.theme", name)
2524 testForTheme(@"/Library/Themes/%@", name)
2525 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
2526
2527 }
2528 }
2529 // }}}
2530 // Merge Info.plist {{{
2531 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2532
2533 for (NSString *theme in Themes_)
2534 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
2535 for (NSString *key in [info allKeys])
2536 if ([Info_ objectForKey:key] == nil)
2537 [Info_ setObject:[info objectForKey:key] forKey:key];
2538 // }}}
2539
2540 // AppSupport {{{
2541 if (MSImageRef image = MSGetImageByName("/System/Library/PrivateFrameworks/AppSupport.framework/AppSupport")) {
2542 NSArray *(*CPBitmapCreateImagesFromPath)(NSString *, CFTypeRef *, void *, void *);
2543 msset(CPBitmapCreateImagesFromPath, image, "_CPBitmapCreateImagesFromPath");
2544 MSHookFunction(CPBitmapCreateImagesFromPath, MSHake(CPBitmapCreateImagesFromPath));
2545 }
2546 // }}}
2547 // AudioToolbox {{{
2548 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
2549 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long, char *, bool &);
2550 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
2551 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
2552
2553 #ifdef __LP64__
2554 bool (*_Z24GetFileNameForThisActionjPcjRb)(unsigned int, char *, unsigned int, bool &);
2555 msset(_Z24GetFileNameForThisActionjPcjRb, image, "__Z24GetFileNameForThisActionjPcjRb");
2556 MSHookFunction(_Z24GetFileNameForThisActionjPcjRb, &$_Z24GetFileNameForThisActionjPcjRb, &__Z24GetFileNameForThisActionjPcjRb);
2557 #else
2558 bool (*_Z24GetFileNameForThisActionmPcmRb)(unsigned long, char *, unsigned long, bool &);
2559 msset(_Z24GetFileNameForThisActionmPcmRb, image, "__Z24GetFileNameForThisActionmPcmRb");
2560 MSHookFunction(_Z24GetFileNameForThisActionmPcmRb, &$_Z24GetFileNameForThisActionmPcmRb, &__Z24GetFileNameForThisActionmPcmRb);
2561 #endif
2562 }
2563 // }}}
2564 // BackBoardServices {{{
2565 if (MSImageRef image = MSGetImageByName("/System/Library/PrivateFrameworks/BackBoardServices.framework/BackBoardServices")) {
2566 void (*BKSDisplayServicesSetSystemAppExitedImagePath)(NSString *path);
2567 msset(BKSDisplayServicesSetSystemAppExitedImagePath, image, "_BKSDisplayServicesSetSystemAppExitedImagePath");
2568 MSHookFunction(BKSDisplayServicesSetSystemAppExitedImagePath, MSHake(BKSDisplayServicesSetSystemAppExitedImagePath));
2569 }
2570 // }}}
2571 // Foundation {{{
2572 if (true) {
2573 if (![identifier isEqualToString:@"com.apple.backupd"]) // XXX: rethink
2574 MSHookFunction(CFBundleCopyResourceURL, MSHake(CFBundleCopyResourceURL));
2575 }
2576 // }}}
2577 // GraphicsServices {{{
2578 if (true) {
2579 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
2580 }
2581 // }}}
2582 // ImageIO {{{
2583 MSImageRef imageio = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO");
2584 if (imageio == NULL)
2585 imageio = MSGetImageByName("/System/Library/PrivateFrameworks/ImageIO.framework/ImageIO");
2586 if (MSImageRef image = imageio) {
2587 void *(*CGImageReadCreateWithFile)(NSString *, int) = NULL;
2588 if (kCFCoreFoundationVersionNumber > 700) // XXX: iOS 6.x
2589 CGImageReadCreateWithFile = NULL;
2590 else {
2591 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
2592 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
2593 }
2594
2595 if (CGImageReadCreateWithFile == NULL) {
2596 void *(*CGImageSourceCreateWithFile)(NSString *, NSDictionary *);
2597 msset(CGImageSourceCreateWithFile, image, "_CGImageSourceCreateWithFile");
2598 MSHookFunction(CGImageSourceCreateWithFile, MSHake(CGImageSourceCreateWithFile));
2599
2600 void *(*CGImageSourceCreateWithURL)(NSURL *, NSDictionary *);
2601 msset(CGImageSourceCreateWithURL, image, "_CGImageSourceCreateWithURL");
2602 MSHookFunction(CGImageSourceCreateWithURL, MSHake(CGImageSourceCreateWithURL));
2603 }
2604 }
2605 // }}}
2606 // SpringBoard {{{
2607 if (SpringBoard_) {
2608 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@3x.png", @"Wallpaper@3x.jpg", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
2609 Papered_ = $getTheme$(Wallpapers_) != nil;
2610 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
2611
2612 CFNotificationCenterAddObserver(
2613 CFNotificationCenterGetDarwinNotifyCenter(),
2614 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, CFNotificationSuspensionBehaviorCoalesce
2615 );
2616
2617 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
2618 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
2619 if (MediaPlayer != nil)
2620 [MediaPlayer load];
2621
2622 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
2623 $MPVideoView = objc_getClass("MPVideoView");
2624 }
2625
2626 SBInitialize();
2627 }
2628 // }}}
2629 // UIKit {{{
2630 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/UIKit.framework/UIKit")) {
2631 #ifdef __LP64__
2632 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v40@0:8{CGPoint=dd}16@32");
2633 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v56@0:8{CGRect={CGSize=dd}{CGSize=dd}}16@48");
2634 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=dd}32@0:8@16d24");
2635 #else
2636 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
2637 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v28@0:4{CGRect={CGSize=ff}{CGSize=ff}}8@24");
2638 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
2639 #endif
2640
2641 WBHookSymbol(image, _UIKitBundle);
2642
2643 if (kCFCoreFoundationVersionNumber < 700)
2644 MSHookFunction(_UIImageWithName, MSHake(_UIImageWithName));
2645
2646 WBHookSymbol(image, _UIApplicationImageWithName);
2647 MSHookFunction(_UIApplicationImageWithName, MSHake(_UIApplicationImageWithName));
2648
2649 WBHookSymbol(image, _UIImageWithNameInDomain);
2650 MSHookFunction(_UIImageWithNameInDomain, MSHake(_UIImageWithNameInDomain));
2651
2652 SEL includeEmoji(@selector(_legacy_drawAtPoint:forWidth:withFont:lineBreakMode:letterSpacing:includeEmoji:));
2653 if (![@"" respondsToSelector:includeEmoji])
2654 includeEmoji = @selector(drawAtPoint:forWidth:withFont:lineBreakMode:letterSpacing:includeEmoji:);
2655 MSHookMessage($NSString, includeEmoji, MSHake(NSString$drawAtPoint$forWidth$withFont$lineBreakMode$letterSpacing$includeEmoji$));
2656
2657 SEL letterSpacing(@selector(_legacy_sizeWithFont:forWidth:lineBreakMode:letterSpacing:));
2658 if (![@"" respondsToSelector:letterSpacing])
2659 letterSpacing = @selector(sizeWithFont:forWidth:lineBreakMode:letterSpacing:);
2660 MSHookMessage($NSString, letterSpacing, MSHake(NSString$sizeWithFont$forWidth$lineBreakMode$letterSpacing$));
2661
2662 SEL sizeWithFont(@selector(_legacy_sizeWithFont:));
2663 if (![@"" respondsToSelector:sizeWithFont])
2664 sizeWithFont = @selector(sizeWithFont:);
2665 MSHookMessage($NSString, sizeWithFont, MSHake(NSString$sizeWithFont$));
2666 }
2667 // }}}
2668
2669 //MSHookFunction(reinterpret_cast<int (*)(const char *, int, mode_t)>(&open), MSHake(open));
2670
2671 [pool release];
2672 }