]> git.saurik.com Git - winterboard.git/blob - Library.mm
Move theme settings cell setup logic to subclass.
[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 ([file isEqualToString:@"Info.plist"])
682 return MSOldCall(resource, type);
683 if (Debug_)
684 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
685 if (NSString *path = $pathForFile$inBundle$(file, self, false, false))
686 return path;
687 return MSOldCall(resource, type);
688 }
689 // }}}
690
691 static void $drawLabel$(NSString *label, CGRect rect, NSString *style, NSString *custom) {
692 bool ellipsis(false);
693 CGFloat max = rect.size.width - 11, width;
694 width:
695 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
696
697 if (width > max) {
698 size_t length([label length]);
699 CGFloat spacing((width - max) / (length - 1));
700
701 if (spacing > 1.25) {
702 ellipsis = true;
703 label = [label substringToIndex:(length - 1)];
704 goto width;
705 }
706
707 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
708 }
709
710 if (ellipsis)
711 label = [label stringByAppendingString:@"..."];
712
713 if (custom != nil)
714 style = [style stringByAppendingString:custom];
715
716 CGSize size = [label sizeWithStyle:style forWidth:rect.size.width];
717 [label drawAtPoint:CGPointMake((rect.size.width - size.width) / 2 + rect.origin.x, rect.origin.y) withStyle:style];
718 }
719
720 static struct WBStringDrawingState {
721 WBStringDrawingState *next_;
722 unsigned count_;
723 NSString *base_;
724 NSString *info_;
725 } *stringDrawingState_;
726
727 extern "C" CGColorSpaceRef CGContextGetFillColorSpace(CGContextRef);
728 extern "C" void CGContextGetFillColor(CGContextRef, CGFloat[]);
729
730 static NSString *WBColorMarkup(size_t number, const CGFloat *components) {
731 CGFloat r, g, b, a;
732
733 switch (number) {
734 case 1:
735 r = components[0];
736 g = components[0];
737 b = components[0];
738 a = components[1];
739 break;
740
741 case 3:
742 r = components[0];
743 g = components[1];
744 b = components[2];
745 a = components[3];
746 break;
747
748 default:
749 return @"";
750 }
751
752 return [NSString stringWithFormat:@"color: rgba(%g, %g, %g, %g)", r * 255, g * 255, b * 255, a];
753 }
754
755 static NSString *WBColorMarkup() {
756 CGContextRef context(UIGraphicsGetCurrentContext());
757 //NSLog(@"XXX:1:%p", context);
758 if (context == NULL)
759 return @"";
760
761 CGColorSpaceRef space(CGContextGetFillColorSpace(context));
762 //NSLog(@"XXX:2:%p", space);
763 if (space == NULL)
764 return @"";
765
766 size_t number(CGColorSpaceGetNumberOfComponents(space));
767 //NSLog(@"XXX:3:%u", number);
768 if (number == 0)
769 return @"";
770
771 CGFloat components[number + 1];
772 CGContextGetFillColor(context, components);
773 return WBColorMarkup(number, components);
774 }
775
776 static NSString *WBColorMarkup(UIColor *uicolor) {
777 if (uicolor == nil)
778 return @"";
779 CGColorRef cgcolor([uicolor CGColor]);
780 if (cgcolor == NULL)
781 return @"";
782
783 CGColorSpaceRef space(CGColorGetColorSpace(cgcolor));
784 //NSLog(@"XXX:2:%p", space);
785 if (space == NULL)
786 return @"";
787
788 size_t number(CGColorGetNumberOfComponents(cgcolor));
789 //NSLog(@"XXX:3:%u", number);
790 if (number == 0)
791 return @"";
792
793 const CGFloat *components(CGColorGetComponents(cgcolor));
794 return WBColorMarkup(number, components);
795 }
796
797 extern "C" NSString *NSStringFromCGPoint(CGPoint rect);
798
799 MSInstanceMessage6(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode,letterSpacing,includeEmoji, CGPoint, point, CGFloat, width, UIFont *, font, UILineBreakMode, mode, CGFloat, spacing, BOOL, emoji) {
800 //NSLog(@"XXX: @\"%@\" %@ %g \"%@\" %u %g %u", self, NSStringFromCGPoint(point), width, font, mode, spacing, emoji);
801
802 WBStringDrawingState *state(stringDrawingState_);
803 if (state == NULL)
804 return MSOldCall(point, width, font, mode, spacing, emoji);
805
806 if (state->count_ != 0 && --state->count_ == 0)
807 stringDrawingState_ = state->next_;
808 if (state->info_ == nil)
809 return MSOldCall(point, width, font, mode, spacing, emoji);
810
811 NSString *info([Info_ objectForKey:state->info_]);
812 if (info == nil)
813 return MSOldCall(point, width, font, mode, spacing, emoji);
814
815 NSString *base(state->base_ ?: @"");
816 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
817 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
818 return CGSizeZero;
819 }
820
821 extern "C" NSString *NSStringFromCGRect(CGRect rect);
822
823 MSInstanceMessageHook7(CGSize, NSString, _drawInRect,withFont,lineBreakMode,alignment,lineSpacing,includeEmoji,truncationRect, CGRect, rect, UIFont *, font, UILineBreakMode, mode, UITextAlignment, alignment, float, spacing, BOOL, emoji, CGRect, truncation) {
824 //NSLog(@"XXX: @\"%@\" %@ \"%@\" %u %u %g %u %@", self, NSStringFromCGRect(rect), font, mode, alignment, spacing, emoji, NSStringFromCGRect(truncation));
825
826 WBStringDrawingState *state(stringDrawingState_);
827 if (state == NULL)
828 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
829
830 if (state->count_ != 0 && --state->count_ == 0)
831 stringDrawingState_ = state->next_;
832 if (state->info_ == nil)
833 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
834
835 NSString *info([Info_ objectForKey:state->info_]);
836 if (info == nil)
837 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
838
839 NSString *textAlign;
840 switch (alignment) {
841 default:
842 case UITextAlignmentLeft:
843 textAlign = @"left";
844 break;
845 case UITextAlignmentCenter:
846 textAlign = @"center";
847 break;
848 case UITextAlignmentRight:
849 textAlign = @"right";
850 break;
851 }
852
853 NSString *base(state->base_ ?: @"");
854 NSString *extra([NSString stringWithFormat:@"text-align: %@", textAlign]);
855
856 if (true)
857 $drawLabel$(self, rect, [NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], WBColorMarkup(), base], info);
858 else
859 [self drawInRect:rect withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
860
861 return CGSizeZero;
862 }
863
864 MSInstanceMessage2(void, NSString, drawInRect,withAttributes, CGRect, rect, NSDictionary *, attributes) {
865 //NSLog(@"XXX: *\"%@\" %@", self, attributes);
866
867 WBStringDrawingState *state(stringDrawingState_);
868 if (state == NULL)
869 return MSOldCall(rect, attributes);
870
871 if (state->count_ != 0 && --state->count_ == 0)
872 stringDrawingState_ = state->next_;
873 if (state->info_ == nil)
874 return MSOldCall(rect, attributes);
875
876 NSString *info([Info_ objectForKey:state->info_]);
877 if (info == nil)
878 return MSOldCall(rect, attributes);
879
880 NSString *base(state->base_ ?: @"");
881
882 UIFont *font([attributes objectForKey:@"NSFont"]);
883 UIColor *color([attributes objectForKey:@"NSColor"]);
884
885 [self drawInRect:rect withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(color), base, info]];
886 }
887
888 extern "C" NSString *NSStringFromCGSize(CGSize size);
889
890 MSInstanceMessage4(CGRect, NSString, boundingRectWithSize,options,attributes,context, CGSize, size, NSInteger, options, NSDictionary *, attributes, id, context) {
891 //NSLog(@"XXX: $\"%@\" %@ 0x%x %@ %@", self, NSStringFromCGSize(size), unsigned(options), attributes, context);
892
893 WBStringDrawingState *state(stringDrawingState_);
894 if (state == NULL)
895 return MSOldCall(size, options, attributes, context);
896
897 if (state->count_ != 0 && --state->count_ == 0)
898 stringDrawingState_ = state->next_;
899 if (state->info_ == nil)
900 return MSOldCall(size, options, attributes, context);
901
902 NSString *info([Info_ objectForKey:state->info_]);
903 if (info == nil)
904 return MSOldCall(size, options, attributes, context);
905
906 NSString *base(state->base_ ?: @"");
907
908 UIFont *font([attributes objectForKey:@"NSFont"]);
909 UIColor *color([attributes objectForKey:@"NSColor"]);
910
911 return (CGRect) {{0, 0}, [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(color), base, info] forWidth:size.width]};
912 }
913
914 MSInstanceMessage4(CGSize, NSString, sizeWithFont,forWidth,lineBreakMode,letterSpacing, UIFont *, font, CGFloat, width, UILineBreakMode, mode, CGFloat, spacing) {
915 //NSLog(@"XXX: #\"%@\" \"%@\" %g %u %g", self, font, width, mode, spacing);
916
917 WBStringDrawingState *state(stringDrawingState_);
918 if (state == NULL)
919 return MSOldCall(font, width, mode, spacing);
920
921 if (state->count_ != 0 && --state->count_ == 0)
922 stringDrawingState_ = state->next_;
923 if (state->info_ == nil)
924 return MSOldCall(font, width, mode, spacing);
925
926 NSString *info([Info_ objectForKey:state->info_]);
927 if (info == nil)
928 return MSOldCall(font, width, mode, spacing);
929
930 NSString *base(state->base_ ?: @"");
931 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
932 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info] forWidth:width];
933 }
934
935 MSInstanceMessage1(CGSize, NSString, sizeWithFont, UIFont *, font) {
936 //NSLog(@"XXX: ?\"%@\"", self);
937
938 WBStringDrawingState *state(stringDrawingState_);
939 if (state == NULL)
940 return MSOldCall(font);
941
942 if (state->count_ != 0 && --state->count_ == 0)
943 stringDrawingState_ = state->next_;
944 if (state->info_ == nil)
945 return MSOldCall(font);
946
947 NSString *info([Info_ objectForKey:state->info_]);
948 if (info == nil)
949 return MSOldCall(font);
950
951 NSString *base(state->base_ ?: @"");
952 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), base, info] forWidth:65535];
953 }
954
955 MSClassMessageHook2(id, SBIconBadgeView, checkoutAccessoryImagesForIcon,location, id, icon, int, location) {
956 WBStringDrawingState badgeState = {NULL, 0, @""
957 , @"BadgeStyle"};
958
959 stringDrawingState_ = &badgeState;
960
961 id images(MSOldCall(icon, location));
962
963 stringDrawingState_ = NULL;
964 return images;
965 }
966
967 MSClassMessageHook2(UIImage *, SBIconAccessoryImage, checkoutAccessoryImageForIcon,location, id, icon, int, location) {
968 if ([self _imageClassForIcon:icon location:location] != $SBIconBadgeImage)
969 return MSOldCall(icon, location);
970
971 WBStringDrawingState badgeState = {NULL, 0, @""
972 , @"BadgeStyle"};
973
974 stringDrawingState_ = &badgeState;
975
976 UIImage *image(MSOldCall(icon, location));
977
978 stringDrawingState_ = NULL;
979 return image;
980 }
981
982 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
983 WBStringDrawingState badgeState = {NULL, 0, @""
984 , @"BadgeStyle"};
985
986 stringDrawingState_ = &badgeState;
987
988 UIImage *image(MSOldCall(text));
989
990 stringDrawingState_ = NULL;
991 return image;
992 }
993
994 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
995 WBStringDrawingState dayState = {NULL, 2, @""
996 // XXX: this is only correct on an iPod dock
997 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
998 , @"CalendarIconDayStyle"};
999
1000 WBStringDrawingState skipState = {&dayState,
1001 unsigned(kCFCoreFoundationVersionNumber > 800 ? 16 : 7)
1002 , nil, nil};
1003
1004 WBStringDrawingState dateState = {&skipState, 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 if (kCFCoreFoundationVersionNumber >= 800) {
2281 WBRename(NSString, drawInRect:withAttributes:, drawInRect$withAttributes$);
2282 WBRename(NSString, boundingRectWithSize:options:attributes:context:, boundingRectWithSize$options$attributes$context$);
2283 }
2284 }
2285
2286 /*MSHook(int, open, const char *path, int oflag, mode_t mode) {
2287 int fd(_open(path, oflag, mode));
2288
2289 static bool no(false);
2290 if (no) return fd;
2291 no = true;
2292
2293 if (strstr(path, "/icon") != NULL)
2294 MSHookProcess(-1, "");
2295
2296 if (fd == -1 && errno == EFAULT)
2297 NSLog(@"open(%p, %#x, %#o) = %d\n", path, oflag, mode, fd);
2298 else
2299 NSLog(@"open(\"%s\", %#x, %#o) = %d\n", path, oflag, mode, fd);
2300
2301 no = false;
2302 return fd;
2303 }*/
2304
2305 MSInitialize {
2306 $objc_setAssociatedObject = reinterpret_cast<void (*)(id, void *, id value, objc_AssociationPolicy)>(dlsym(RTLD_DEFAULT, "objc_setAssociatedObject"));
2307 $objc_getAssociatedObject = reinterpret_cast<id (*)(id, void *)>(dlsym(RTLD_DEFAULT, "objc_getAssociatedObject"));
2308 $objc_removeAssociatedObjects = reinterpret_cast<void (*)(id)>(dlsym(RTLD_DEFAULT, "objc_removeAssociatedObjects"));
2309
2310 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2311
2312 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
2313 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
2314
2315 Manager_ = [[NSFileManager defaultManager] retain];
2316 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
2317
2318 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
2319
2320 // Load Settings.plist {{{
2321 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
2322 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
2323 SummerBoard_ = [value boolValue];
2324 else
2325 SummerBoard_ = true;
2326
2327 if (NSNumber *value = [settings objectForKey:@"Debug"])
2328 Debug_ = [value boolValue];
2329 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
2330 UIDebug_ = [value boolValue];
2331
2332 NSArray *themes([settings objectForKey:@"Themes"]);
2333 if (themes == nil)
2334 if (NSString *theme = [settings objectForKey:@"Theme"])
2335 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
2336 theme, @"Name",
2337 [NSNumber numberWithBool:true], @"Active",
2338 nil]];
2339
2340 if (themes != nil)
2341 for (NSDictionary *theme in themes) {
2342 NSNumber *active([theme objectForKey:@"Active"]);
2343 if (![active boolValue])
2344 continue;
2345
2346 NSString *name([theme objectForKey:@"Name"]);
2347 if (name == nil)
2348 continue;
2349
2350 #define testForTheme(format...) \
2351 { \
2352 NSString *path = [NSString stringWithFormat:format]; \
2353 if ([Manager_ fileExistsAtPath:path]) { \
2354 [Themes_ addObject:path]; \
2355 continue; \
2356 } \
2357 }
2358
2359 testForTheme(@"/Library/Themes/%@.theme", name)
2360 testForTheme(@"/Library/Themes/%@", name)
2361 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
2362
2363 }
2364 }
2365 // }}}
2366 // Merge Info.plist {{{
2367 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2368
2369 for (NSString *theme in Themes_)
2370 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
2371 for (NSString *key in [info allKeys])
2372 if ([Info_ objectForKey:key] == nil)
2373 [Info_ setObject:[info objectForKey:key] forKey:key];
2374 // }}}
2375
2376 // AppSupport {{{
2377 if (MSImageRef image = MSGetImageByName("/System/Library/PrivateFrameworks/AppSupport.framework/AppSupport")) {
2378 NSArray *(*CPBitmapCreateImagesFromPath)(NSString *, NSDictionary **, void *, void *);
2379 msset(CPBitmapCreateImagesFromPath, image, "_CPBitmapCreateImagesFromPath");
2380 MSHookFunction(CPBitmapCreateImagesFromPath, MSHake(CPBitmapCreateImagesFromPath));
2381 }
2382 // }}}
2383 // AudioToolbox {{{
2384 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
2385 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long, char *, bool &);
2386 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
2387 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
2388
2389 bool (*_Z24GetFileNameForThisActionmPcmRb)(unsigned long, char *, unsigned long, bool &);
2390 msset(_Z24GetFileNameForThisActionmPcmRb, image, "__Z24GetFileNameForThisActionmPcmRb");
2391 MSHookFunction(_Z24GetFileNameForThisActionmPcmRb, &$_Z24GetFileNameForThisActionmPcmRb, &__Z24GetFileNameForThisActionmPcmRb);
2392 }
2393 // }}}
2394 // BackBoardServices {{{
2395 if (MSImageRef image = MSGetImageByName("/System/Library/PrivateFrameworks/BackBoardServices.framework/BackBoardServices")) {
2396 void (*BKSDisplayServicesSetSystemAppExitedImagePath)(NSString *path);
2397 msset(BKSDisplayServicesSetSystemAppExitedImagePath, image, "_BKSDisplayServicesSetSystemAppExitedImagePath");
2398 MSHookFunction(BKSDisplayServicesSetSystemAppExitedImagePath, MSHake(BKSDisplayServicesSetSystemAppExitedImagePath));
2399 }
2400 // }}}
2401 // GraphicsServices {{{
2402 if (true) {
2403 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
2404 }
2405 // }}}
2406 // ImageIO {{{
2407 MSImageRef imageio = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO");
2408 if (imageio == NULL)
2409 imageio = MSGetImageByName("/System/Library/PrivateFrameworks/ImageIO.framework/ImageIO");
2410 if (MSImageRef image = imageio) {
2411 void *(*CGImageReadCreateWithFile)(NSString *, int) = NULL;
2412 if (kCFCoreFoundationVersionNumber > 700) // XXX: iOS 6.x
2413 CGImageReadCreateWithFile = NULL;
2414 else {
2415 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
2416 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
2417 }
2418
2419 if (CGImageReadCreateWithFile == NULL) {
2420 void *(*CGImageSourceCreateWithFile)(NSString *, NSDictionary *);
2421 msset(CGImageSourceCreateWithFile, image, "_CGImageSourceCreateWithFile");
2422 MSHookFunction(CGImageSourceCreateWithFile, MSHake(CGImageSourceCreateWithFile));
2423
2424 void *(*CGImageSourceCreateWithURL)(NSURL *, NSDictionary *);
2425 msset(CGImageSourceCreateWithURL, image, "_CGImageSourceCreateWithURL");
2426 MSHookFunction(CGImageSourceCreateWithURL, MSHake(CGImageSourceCreateWithURL));
2427 }
2428 }
2429 // }}}
2430 // SpringBoard {{{
2431 if (SpringBoard_) {
2432 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
2433 Papered_ = $getTheme$(Wallpapers_) != nil;
2434 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
2435
2436 CFNotificationCenterAddObserver(
2437 CFNotificationCenterGetDarwinNotifyCenter(),
2438 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, CFNotificationSuspensionBehaviorCoalesce
2439 );
2440
2441 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
2442 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
2443 if (MediaPlayer != nil)
2444 [MediaPlayer load];
2445
2446 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
2447 $MPVideoView = objc_getClass("MPVideoView");
2448 }
2449
2450 SBInitialize();
2451 }
2452 // }}}
2453 // UIKit {{{
2454 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/UIKit.framework/UIKit")) {
2455 #ifdef __LP64__
2456 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v40@0:8{CGPoint=dd}16@32");
2457 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v56@0:8{CGRect={CGSize=dd}{CGSize=dd}}16@48");
2458 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=dd}32@0:8@16d24");
2459 #else
2460 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
2461 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v28@0:4{CGRect={CGSize=ff}{CGSize=ff}}8@24");
2462 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
2463 #endif
2464
2465 WBHookSymbol(image, _UIKitBundle);
2466 WBHookSymbol(image, _UIPackedImageTableGetIdentifierForName);
2467 WBHookSymbol(image, _UISharedImageNameGetIdentifier);
2468
2469 MSHookFunction(_UIImageWithName, MSHake(_UIImageWithName));
2470
2471 WBHookSymbol(image, _UIApplicationImageWithName);
2472 MSHookFunction(_UIApplicationImageWithName, MSHake(_UIApplicationImageWithName));
2473
2474 WBHookSymbol(image, _UIImageWithNameInDomain);
2475 MSHookFunction(_UIImageWithNameInDomain, MSHake(_UIImageWithNameInDomain));
2476
2477 WBHookSymbol(image, _UIImageWithNameUsingCurrentIdiom);
2478 MSHookFunction(_UIImageWithNameUsingCurrentIdiom, MSHake(_UIImageWithNameUsingCurrentIdiom));
2479
2480 WBHookSymbol(image, _UIImageWithDeviceSpecificName);
2481 MSHookFunction(_UIImageWithDeviceSpecificName, MSHake(_UIImageWithDeviceSpecificName));
2482
2483 SEL includeEmoji(@selector(_legacy_drawAtPoint:forWidth:withFont:lineBreakMode:letterSpacing:includeEmoji:));
2484 if (![@"" respondsToSelector:includeEmoji])
2485 includeEmoji = @selector(drawAtPoint:forWidth:withFont:lineBreakMode:letterSpacing:includeEmoji:);
2486 MSHookMessage($NSString, includeEmoji, MSHake(NSString$drawAtPoint$forWidth$withFont$lineBreakMode$letterSpacing$includeEmoji$));
2487
2488 SEL letterSpacing(@selector(_legacy_sizeWithFont:forWidth:lineBreakMode:letterSpacing:));
2489 if (![@"" respondsToSelector:letterSpacing])
2490 letterSpacing = @selector(sizeWithFont:forWidth:lineBreakMode:letterSpacing:);
2491 MSHookMessage($NSString, letterSpacing, MSHake(NSString$sizeWithFont$forWidth$lineBreakMode$letterSpacing$));
2492
2493 SEL sizeWithFont(@selector(_legacy_sizeWithFont:));
2494 if (![@"" respondsToSelector:sizeWithFont])
2495 sizeWithFont = @selector(sizeWithFont:);
2496 MSHookMessage($NSString, sizeWithFont, MSHake(NSString$sizeWithFont$));
2497 }
2498 // }}}
2499
2500 //MSHookFunction(reinterpret_cast<int (*)(const char *, int, mode_t)>(&open), MSHake(open));
2501
2502 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
2503 NSError *error(nil);
2504 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
2505 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
2506 nil] error:&error])
2507 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);
2508 }
2509
2510 [pool release];
2511 }