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