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