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