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