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