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