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