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