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