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