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