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