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