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