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