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