]> git.saurik.com Git - winterboard.git/blob - Library.mm
Finish re-integrating WinterBoard label code.
[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 void $drawLabel$(NSString *label, CGRect rect, NSString *style, NSString *custom) {
680 bool ellipsis(false);
681 float max = rect.size.width - 11, width;
682 width:
683 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
684
685 if (width > max) {
686 size_t length([label length]);
687 float spacing((width - max) / (length - 1));
688
689 if (spacing > 1.25) {
690 ellipsis = true;
691 label = [label substringToIndex:(length - 1)];
692 goto width;
693 }
694
695 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
696 }
697
698 if (ellipsis)
699 label = [label stringByAppendingString:@"..."];
700
701 if (custom != nil)
702 style = [style stringByAppendingString:custom];
703
704 CGSize size = [label sizeWithStyle:style forWidth:rect.size.width];
705 [label drawAtPoint:CGPointMake((rect.size.width - size.width) / 2 + rect.origin.x, rect.origin.y) withStyle:style];
706 }
707
708 static struct WBStringDrawingState {
709 WBStringDrawingState *next_;
710 unsigned count_;
711 NSString *base_;
712 NSString *info_;
713 } *stringDrawingState_;
714
715 MSInstanceMessageHook6(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode,letterSpacing,includeEmoji, CGPoint, point, float, width, UIFont *, font, UILineBreakMode, mode, float, spacing, BOOL, emoji) {
716 WBStringDrawingState *state(stringDrawingState_);
717 if (state == NULL)
718 return MSOldCall(point, width, font, mode, spacing, emoji);
719
720 if (--state->count_ == 0)
721 stringDrawingState_ = state->next_;
722 if (state->info_ == nil)
723 return MSOldCall(point, width, font, mode, spacing, emoji);
724
725 NSString *info([Info_ objectForKey:state->info_]);
726 if (info == nil)
727 return MSOldCall(point, width, font, mode, spacing, emoji);
728
729 NSString *base(state->base_ ?: @"");
730 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
731 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], extra, base, info]];
732 return CGSizeZero;
733 }
734
735 MSInstanceMessageHook7(CGSize, NSString, _drawInRect,withFont,lineBreakMode,alignment,lineSpacing,includeEmoji,truncationRect, CGRect, rect, UIFont *, font, UILineBreakMode, mode, UITextAlignment, alignment, float, spacing, BOOL, emoji, CGRect, truncation) {
736 WBStringDrawingState *state(stringDrawingState_);
737 if (state == NULL)
738 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
739
740 if (--state->count_ == 0)
741 stringDrawingState_ = state->next_;
742 if (state->info_ == nil)
743 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
744
745 NSString *info([Info_ objectForKey:state->info_]);
746 if (info == nil)
747 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
748
749 NSString *textAlign;
750 switch (alignment) {
751 default:
752 case UITextAlignmentLeft:
753 textAlign = @"left";
754 break;
755 case UITextAlignmentCenter:
756 textAlign = @"center";
757 break;
758 case UITextAlignmentRight:
759 textAlign = @"right";
760 break;
761 }
762
763 NSString *base(state->base_ ?: @"");
764 NSString *extra([NSString stringWithFormat:@"text-align: %@", textAlign]);
765
766 if (true)
767 $drawLabel$(self, rect, [NSString stringWithFormat:@"%@;%@", [font markupDescription], base], info);
768 else
769 [self drawInRect:rect withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], extra, base, info]];
770
771 return CGSizeZero;
772 }
773
774 MSInstanceMessageHook4(CGSize, NSString, sizeWithFont,forWidth,lineBreakMode,letterSpacing, UIFont *, font, float, width, UILineBreakMode, mode, float, spacing) {
775 WBStringDrawingState *state(stringDrawingState_);
776 if (state == NULL)
777 return MSOldCall(font, width, mode, spacing);
778
779 if (--state->count_ == 0)
780 stringDrawingState_ = state->next_;
781 if (state->info_ == nil)
782 return MSOldCall(font, width, mode, spacing);
783
784 NSString *info([Info_ objectForKey:state->info_]);
785 if (info == nil)
786 return MSOldCall(font, width, mode, spacing);
787
788 NSString *base(state->base_ ?: @"");
789 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
790 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], extra, base, info] forWidth:width];
791 }
792
793 MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) {
794 WBStringDrawingState *state(stringDrawingState_);
795 if (state == NULL)
796 return MSOldCall(font);
797
798 if (--state->count_ == 0)
799 stringDrawingState_ = state->next_;
800 if (state->info_ == nil)
801 return MSOldCall(font);
802
803 NSString *info([Info_ objectForKey:state->info_]);
804 if (info == nil)
805 return MSOldCall(font);
806
807 NSString *base(state->base_ ?: @"");
808 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info] forWidth:65535];
809 }
810
811 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
812 WBStringDrawingState badgeState = {NULL, 1, @""
813 "color: white;"
814 , @"BadgeStyle"};
815
816 stringDrawingState_ = &badgeState;
817
818 UIImage *image(MSOldCall(text));
819
820 stringDrawingState_ = NULL;
821 return image;
822 }
823
824 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
825 WBStringDrawingState dayState = {NULL, 2, @""
826 "color: white;"
827 // XXX: this is only correct on an iPod dock
828 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
829 , @"CalendarIconDayStyle"};
830
831 WBStringDrawingState sizeState = {&dayState, 7, nil, nil};
832
833 WBStringDrawingState dateState = {&sizeState, 2, @""
834 "color: #333333;"
835 , @"CalendarIconDateStyle"};
836
837 stringDrawingState_ = &dateState;
838
839 UIImage *image(MSOldCall(type));
840
841 stringDrawingState_ = NULL;
842 return image;
843 }
844
845 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
846 NSBundle *bundle([NSBundle mainBundle]);
847
848 CFLocaleRef locale(CFLocaleCopyCurrent());
849 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
850 CFRelease(locale);
851
852 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
853
854 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
855 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
856 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
857 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
858
859 CFRelease(now);
860
861 CFRelease(formatter);
862
863 NSString *datestyle([@""
864 "font-family: Helvetica; "
865 "font-weight: bold; "
866 "color: #333333; "
867 "alpha: 1.0; "
868 "" stringByAppendingString:(IsWild_
869 ? @"font-size: 54px; "
870 : @"font-size: 39px; "
871 )]);
872
873 NSString *daystyle([@""
874 "font-family: Helvetica; "
875 "font-weight: bold; "
876 "color: white; "
877 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
878 "" stringByAppendingString:(IsWild_
879 ? @"font-size: 11px; "
880 : @"font-size: 9px; "
881 )]);
882
883 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
884 datestyle = [datestyle stringByAppendingString:style];
885 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
886 daystyle = [daystyle stringByAppendingString:style];
887
888 float width([self bounds].size.width);
889 float leeway(10);
890 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
891 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
892
893 unsigned base0(IsWild_ ? 89 : 70);
894 if ($GSFontGetUseLegacyFontMetrics())
895 base0 = base0 + 1;
896 unsigned base1(IsWild_ ? 18 : 16);
897
898 if (Four_) {
899 ++base0;
900 ++base1;
901 }
902
903 [(NSString *)date drawAtPoint:CGPointMake(
904 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
905 ) withStyle:datestyle];
906
907 [(NSString *)day drawAtPoint:CGPointMake(
908 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
909 ) withStyle:daystyle];
910
911 CFRelease(date);
912 CFRelease(day);
913 }
914
915 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
916 void $setBarStyle$_(NSString *name, int &style) {
917 if (Debug_)
918 NSLog(@"WB:Debug:%@Style:%d", name, style);
919 NSNumber *number = nil;
920 if (number == nil)
921 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
922 if (number == nil)
923 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
924 if (number != nil) {
925 style = [number intValue];
926 if (Debug_)
927 NSLog(@"WB:Debug:%@Style=%d", name, style);
928 }
929 }
930
931 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
932 $setBarStyle$_(@"Toolbar", style);
933 return MSOldCall(style);
934 }
935
936 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
937 $setBarStyle$_(@"NavigationBar", style);
938 return MSOldCall(style);
939 }
940 // }}}
941
942 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
943 [[self superview] setBackgroundColor:[UIColor clearColor]];
944 _SBButtonBar$didMoveToSuperview(self, sel);
945 }
946
947 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
948 [[self superview] setBackgroundColor:[UIColor clearColor]];
949 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
950 }
951
952 static NSArray *Wallpapers_;
953 static bool Papered_;
954 static bool Docked_;
955 static bool SMSBackgrounded_;
956 static NSString *WallpaperFile_;
957 static UIImageView *WallpaperImage_;
958 static UIWebDocumentView *WallpaperPage_;
959 static NSURL *WallpaperURL_;
960
961 #define _release(object) \
962 do if (object != nil) { \
963 [object release]; \
964 object = nil; \
965 } while (false)
966
967 static UIImage *$getImage$(NSString *path) {
968 UIImage *image([UIImage imageWithContentsOfFile:path]);
969
970 unsigned scale($getScale$(path));
971 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
972 [image setScale:scale];
973
974 return image;
975 }
976
977 static UIImage *$getDefaultDesktopImage$() {
978 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
979 return $getImage$(path);
980 return nil;
981 }
982
983 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
984 return $getDefaultDesktopImage$() ?: MSOldCall();
985 }
986
987 MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
988 return $getDefaultDesktopImage$() ?: MSOldCall();
989 }
990
991 MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
992 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
993 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
994 if (UIImage *image = $getDefaultDesktopImage$()) {
995 [self setImage:image];
996 return;
997 }
998
999 break;
1000 }
1001
1002 MSOldCall();
1003 }
1004
1005 // %hook -[SBUIController init] {{{
1006 MSInstanceMessageHook0(id, SBUIController, init) {
1007 self = MSOldCall();
1008 if (self == nil)
1009 return nil;
1010
1011 NSString *paper($getTheme$(Wallpapers_));
1012 if (paper != nil)
1013 paper = [paper stringByDeletingLastPathComponent];
1014
1015 {
1016 size_t size;
1017 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
1018 char *machine = new char[size];
1019
1020 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
1021 perror("sysctlbyname(\"hw.machine\", ?)");
1022 delete [] machine;
1023 machine = NULL;
1024 }
1025
1026 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
1027 }
1028
1029 if (Debug_)
1030 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
1031
1032 if (paper != nil) {
1033 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
1034 if (&_wallpaperView != NULL) {
1035 [_wallpaperView removeFromSuperview];
1036 [_wallpaperView release];
1037 _wallpaperView = nil;
1038 }
1039 }
1040
1041 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
1042 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
1043
1044 UIView **player;
1045 if (&_contentLayer != NULL)
1046 player = &_contentLayer;
1047 else if (&_contentView != NULL)
1048 player = &_contentView;
1049 else
1050 player = NULL;
1051 UIView *layer(player == NULL ? nil : *player);
1052
1053 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
1054 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
1055 [window setContentView:content];
1056
1057 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
1058 [window setBackgroundColor:[_window backgroundColor]];
1059 [_window setBackgroundColor:[UIColor clearColor]];
1060
1061 [window setLevel:-1000];
1062 [window setHidden:NO];
1063
1064 /*if (player != NULL)
1065 *player = content;*/
1066
1067 [content setBackgroundColor:[layer backgroundColor]];
1068 [layer setBackgroundColor:[UIColor clearColor]];
1069
1070 UIView *indirect;
1071 if (!SummerBoard_ || !IsWild_)
1072 indirect = content;
1073 else {
1074 CGRect bounds([content bounds]);
1075 bounds.origin.y = -30;
1076 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
1077 [content addSubview:indirect];
1078 [indirect zoomToScale:2.4];
1079 }
1080
1081 _release(WallpaperFile_);
1082 _release(WallpaperImage_);
1083 _release(WallpaperPage_);
1084 _release(WallpaperURL_);
1085
1086 if (paper != nil) {
1087 NSArray *themes([NSArray arrayWithObject:paper]);
1088
1089 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1090 #if UseAVController
1091 NSError *error;
1092
1093 static AVController *controller_(nil);
1094 if (controller_ == nil) {
1095 AVQueue *queue([AVQueue avQueue]);
1096 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1097 }
1098
1099 AVQueue *queue([controller_ queue]);
1100
1101 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1102 [controller_ setLayer:[video _layer]];
1103
1104 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1105 [queue appendItem:item error:&error];
1106
1107 [controller_ play:&error];
1108 #elif UseMPMoviePlayerController
1109 NSURL *url([NSURL fileURLWithPath:path]);
1110 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1111 controller.movieControlMode = MPMovieControlModeHidden;
1112 [controller play];
1113 #else
1114 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1115 [video setMovieWithPath:path];
1116 [video setRepeatMode:1];
1117 [video setRepeatGap:-1];
1118 [video playFromBeginning];;
1119 #endif
1120
1121 [indirect addSubview:video];
1122 }
1123
1124 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1125 if (UIImage *image = $getImage$(path)) {
1126 WallpaperFile_ = [path retain];
1127 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1128 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1129 [WallpaperImage_ setAlpha:[number floatValue]];
1130 [indirect addSubview:WallpaperImage_];
1131 }
1132 }
1133
1134 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1135 CGRect bounds = [indirect bounds];
1136
1137 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1138 [view setAutoresizes:true];
1139
1140 WallpaperPage_ = [view retain];
1141 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1142
1143 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1144
1145 [view setBackgroundColor:[UIColor clearColor]];
1146 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1147 [view setDrawsBackground:NO];
1148 [[view webView] setDrawsBackground:NO];
1149
1150 [indirect addSubview:view];
1151 }
1152 }
1153
1154 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1155 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1156 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1157 if ([Manager_ fileExistsAtPath:html]) {
1158 CGRect bounds = [indirect bounds];
1159
1160 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1161 [view setAutoresizes:true];
1162
1163 NSURL *url = [NSURL fileURLWithPath:html];
1164 [view loadRequest:[NSURLRequest requestWithURL:url]];
1165
1166 [view setBackgroundColor:[UIColor clearColor]];
1167 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1168 [view setDrawsBackground:NO];
1169 [[view webView] setDrawsBackground:NO];
1170
1171 [indirect addSubview:view];
1172 }
1173 }
1174
1175 return self;
1176 }
1177 // }}}
1178
1179 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1180 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1181 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1182
1183 if (path != nil && _backgroundView != nil)
1184 path = nil;
1185
1186 _SBAwayView$updateDesktopImage$(self, sel, image);
1187
1188 if (path != nil) {
1189 CGRect bounds = [self bounds];
1190
1191 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1192 [view setAutoresizes:true];
1193
1194 if (WallpaperPage_ != nil)
1195 [WallpaperPage_ release];
1196 WallpaperPage_ = [view retain];
1197
1198 if (WallpaperURL_ != nil)
1199 [WallpaperURL_ release];
1200 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1201
1202 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1203
1204 [[view webView] setDrawsBackground:false];
1205 [view setBackgroundColor:[UIColor clearColor]];
1206
1207 [self insertSubview:view aboveSubview:_backgroundView];
1208 }
1209 }
1210
1211 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1212 extern "C" CGColorRef CGGStateGetFillColor(void *);
1213 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1214 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1215
1216 /* WBTimeLabel {{{ */
1217 @interface WBTimeLabel : NSProxy {
1218 NSString *time_;
1219 _transient SBStatusBarTimeView *view_;
1220 }
1221
1222 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1223
1224 @end
1225
1226 @implementation WBTimeLabel
1227
1228 - (void) dealloc {
1229 [time_ release];
1230 [super dealloc];
1231 }
1232
1233 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1234 time_ = [time retain];
1235 view_ = view;
1236 return self;
1237 }
1238
1239 - (NSString *) description {
1240 return time_;
1241 }
1242
1243 WBDelegate(time_)
1244
1245 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1246 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1247 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1248
1249 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1250 "font-family: Helvetica; "
1251 "font-weight: bold; "
1252 "font-size: 14px; "
1253 "color: %@; "
1254 "%@", _mode ? @"white" : @"black", custom]];
1255
1256 return CGSizeZero;
1257 }
1258
1259 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1260 }
1261
1262 @end
1263 /* }}} */
1264 /* WBBadgeLabel {{{ */
1265 @interface WBBadgeLabel : NSProxy {
1266 NSString *badge_;
1267 }
1268
1269 - (id) initWithBadge:(NSString *)badge;
1270 - (NSString *) description;
1271
1272 @end
1273
1274 @implementation WBBadgeLabel
1275
1276 - (void) dealloc {
1277 [badge_ release];
1278 [super dealloc];
1279 }
1280
1281 - (id) initWithBadge:(NSString *)badge {
1282 badge_ = [badge retain];
1283 return self;
1284 }
1285
1286 - (NSString *) description {
1287 return [badge_ description];
1288 }
1289
1290 WBDelegate(badge_)
1291
1292 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1293 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1294 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1295 "font-family: Helvetica; "
1296 "font-weight: bold; "
1297 "font-size: 17px; "
1298 "color: white; "
1299 "%@", custom]];
1300
1301 return CGSizeZero;
1302 }
1303
1304 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1305 }
1306
1307 @end
1308 /* }}} */
1309
1310 // IconAlpha {{{
1311 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1312 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1313 alpha = [number floatValue];
1314 return MSOldCall(alpha);
1315 }
1316
1317 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1318 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1319 alpha = [number floatValue];
1320 return MSOldCall(alpha);
1321 }
1322
1323 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1324 if ((self = MSOldCall()) != nil) {
1325 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1326 // XXX: note: this is overridden above, which is silly
1327 float alpha([number floatValue]);
1328 [self setIconImageAlpha:alpha];
1329 [self setIconLabelAlpha:alpha];
1330 }
1331 } return self;
1332 }
1333
1334 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1335 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1336 alpha = [number floatValue];
1337 return MSOldCall(alpha);
1338 }
1339 // }}}
1340
1341 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1342 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1343 id &_badge(MSHookIvar<id>(self, "_badge"));
1344 if (_badge != nil)
1345 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1346 _badge = label;
1347 } return self;
1348 }
1349
1350 void SBStatusBarController$setStatusBarMode(int &mode) {
1351 if (Debug_)
1352 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1353 if (mode < 100) // 104:hidden 105:glowing
1354 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1355 mode = [number intValue];
1356 }
1357
1358 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1359 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1360 SBStatusBarController$setStatusBarMode(mode);
1361 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1362 }*/
1363
1364 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1365 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1366 SBStatusBarController$setStatusBarMode(mode);
1367 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1368 }
1369
1370 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) {
1371 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1372 SBStatusBarController$setStatusBarMode(mode);
1373 //NSLog(@"mode=%u", mode);
1374 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1375 }
1376
1377 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1378 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1379 mode = [number intValue];
1380 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1381 }*/
1382
1383 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1384 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1385 if (Debug_)
1386 NSLog(@"operatorNameStyle= %@", style);
1387 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1388 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1389 return style;
1390 }
1391
1392 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1393 if (Debug_)
1394 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1395 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1396 }
1397
1398 // XXX: replace this with [SBStatusBarTimeView tile]
1399 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1400 id &_time(MSHookIvar<id>(self, "_time"));
1401 if (_time != nil && [_time class] != [WBTimeLabel class])
1402 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1403 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1404 }
1405
1406 @interface UIView (WinterBoard)
1407 - (bool) wb$isWBImageView;
1408 - (void) wb$logHierarchy;
1409 - (void) wb$setBackgroundColor:(UIColor *)color;
1410 @end
1411
1412 @implementation UIView (WinterBoard)
1413
1414 - (bool) wb$isWBImageView {
1415 return false;
1416 }
1417
1418 - (void) wb$logHierarchy {
1419 WBLogHierarchy(self);
1420 }
1421
1422 - (void) wb$setBackgroundColor:(UIColor *)color {
1423 [self setBackgroundColor:color];
1424 for (UIView *child in [self subviews])
1425 [child wb$setBackgroundColor:color];
1426 }
1427
1428 @end
1429
1430 @interface WBImageView : UIImageView {
1431 }
1432
1433 - (bool) wb$isWBImageView;
1434 - (void) wb$updateFrame;
1435 @end
1436
1437 @implementation WBImageView
1438
1439 - (bool) wb$isWBImageView {
1440 return true;
1441 }
1442
1443 - (void) wb$updateFrame {
1444 CGRect frame([self frame]);
1445 frame.origin.y = 0;
1446
1447 for (UIView *view(self); ; ) {
1448 view = [view superview];
1449 if (view == nil)
1450 break;
1451 frame.origin.y -= [view frame].origin.y;
1452 }
1453
1454 [self setFrame:frame];
1455 }
1456
1457 @end
1458
1459 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1460 NSArray *subviews([self subviews]);
1461 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1462 if (view != nil && [view wb$isWBImageView])
1463 [view wb$updateFrame];
1464 _SBIconList$setFrame$(self, sel, frame);
1465 }
1466
1467 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1468 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1469 NSArray *lists([_iconModel iconLists]);
1470
1471 for (unsigned i(0), e([lists count]); i != e; ++i)
1472 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]])) {
1473 SBIconList *list([lists objectAtIndex:i]);
1474 NSArray *subviews([list subviews]);
1475
1476 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1477 if (view == nil || ![view wb$isWBImageView]) {
1478 view = [[[WBImageView alloc] init] autorelease];
1479 [list insertSubview:view atIndex:0];
1480 }
1481
1482 UIImage *image([UIImage imageWithContentsOfFile:path]);
1483
1484 CGRect frame([view frame]);
1485 frame.size = [image size];
1486 [view setFrame:frame];
1487
1488 [view setImage:image];
1489 [view wb$updateFrame];
1490 }
1491
1492 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1493 }
1494
1495 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1496 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1497 if (self != nil)
1498 [self setClipsToBounds:NO];
1499 return self;
1500 }
1501
1502 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1503 static bool gssc(false);
1504 if (!gssc) {
1505 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1506 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1507 gssc = true;
1508
1509 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1510 [Info_ setObject:[NSNumber numberWithBool:(
1511 !Papered_ ||
1512 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1513 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1514 )] forKey:@"UndockedIconLabels"];
1515 }
1516
1517 id &_label(MSHookIvar<id>(self, "_label"));
1518 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1519 docked = true;
1520
1521 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1522 [_label setInDock:docked];
1523
1524 _SBIconLabel$setInDock$(self, sel, docked);
1525 [self setNeedsDisplay];
1526 }
1527
1528 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1529 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1530 }
1531
1532 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1533 _SBDockIconListView$setFrame$(self, sel, frame);
1534 }
1535
1536 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1537 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1538 NSString *identifier = [self bundleIdentifier];
1539 NSLocale *locale = [NSLocale currentLocale];
1540 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1541 if (Debug_)
1542 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1543 NSString *file = table == nil ? @"Localizable" : table;
1544 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1545 NSDictionary *strings;
1546 if ((strings = [Strings_ objectForKey:name]) != nil) {
1547 if (static_cast<id>(strings) != [NSNull null]) strings:
1548 if (NSString *value = [strings objectForKey:key])
1549 return value;
1550 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1551 language, file
1552 ], self, false)) {
1553 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1554 [Strings_ setObject:[strings autorelease] forKey:name];
1555 goto strings;
1556 } else goto null;
1557 } else null:
1558 [Strings_ setObject:[NSNull null] forKey:name];
1559 return MSOldCall(key, value, table);
1560 }
1561 // }}}
1562 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1563 MSClassHook(WebCoreFrameBridge)
1564
1565 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1566 if (node == nil)
1567 return CGSizeZero;
1568 void **core(reinterpret_cast<void **>([node _node]));
1569 if (core == NULL || core[6] == NULL)
1570 return CGSizeZero;
1571 return MSOldCall(node, width);
1572 }
1573 // }}}
1574
1575 MSInstanceMessage1(void, SBIconLabel, drawRect, CGRect, rect) {
1576 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1577
1578 int docked;
1579 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1580 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1581
1582 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1583
1584 NSString *style = [NSString stringWithFormat:@""
1585 "font-family: Helvetica; "
1586 "font-weight: bold; "
1587 "color: %@; %@"
1588 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1589 ? @"font-size: 12px; "
1590 : @"font-size: 11px; "
1591 )];
1592
1593 if (IsWild_)
1594 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1595 else if (docked)
1596 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1597
1598 NSString *custom([Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")]);
1599
1600 $drawLabel$(label, [self bounds], style, custom);
1601 }
1602
1603 MSInstanceMessage0(CGImageRef, SBIconLabel, buildLabelImage) {
1604 bool docked((MSHookIvar<unsigned>(self, "_inDock") & 0x2) != 0);
1605
1606 WBStringDrawingState labelState = {NULL, 0, [NSString stringWithFormat:@""
1607 "color: %@;"
1608 ,
1609 (docked || !SummerBoard_ ? @"white" : @"#b3b3b3")
1610 ], docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1611
1612 stringDrawingState_ = &labelState;
1613
1614 CGImageRef image(MSOldCall());
1615
1616 stringDrawingState_ = NULL;
1617 return image;
1618 }
1619
1620 // ChatKit {{{
1621 MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1622 if ((self = MSOldCall(frame, delegate)) != nil) {
1623 [self setBackgroundColor:[UIColor clearColor]];
1624 } return self;
1625 }
1626
1627 MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1628 return SMSBackgrounded_ ? NO : MSOldCall();
1629 }
1630
1631 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1632 [self wb$setBackgroundColor:[UIColor clearColor]];
1633 return MSOldCall();
1634 }
1635
1636 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1637 MSOldCall(balloon);
1638 [balloon setBackgroundColor:[UIColor clearColor]];
1639 }
1640
1641 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1642 MSOldCall([UIColor clearColor]);
1643 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1644 }
1645
1646 // iOS >= 5.0
1647 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1648 if ((self = MSOldCall(style, reuse)) != nil) {
1649 [self setBackgroundColor:[UIColor clearColor]];
1650 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1651 } return self;
1652 }
1653
1654 // iOS << 5.0
1655 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1656 if ((self = MSOldCall(style, reuse)) != nil) {
1657 [self setBackgroundColor:[UIColor clearColor]];
1658 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1659 } return self;
1660 }
1661
1662 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1663 if ((self = MSOldCall(style, reuse)) != nil) {
1664 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1665 [_label setBackgroundColor:[UIColor clearColor]];
1666 } return self;
1667 }
1668
1669 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1670 MSOldCall(UITableViewCellSeparatorStyleNone);
1671 }
1672
1673 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1674 if ((self = MSOldCall(frame, style)) != nil) {
1675 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1676 } return self;
1677 }
1678
1679 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1680 MSOldCall();
1681
1682 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1683 if (UIImage *image = $getImage$(path)) {
1684 SMSBackgrounded_ = true;
1685
1686 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1687 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1688 UIView *table;
1689 if (&_transcriptTable != NULL)
1690 table = _transcriptTable;
1691 else if (&_transcriptLayer != NULL)
1692 table = _transcriptLayer;
1693 else
1694 table = nil;
1695
1696 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1697 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1698
1699 if (table == nil)
1700 [placard insertSubview:background atIndex:0];
1701 else {
1702 [table setBackgroundColor:[UIColor clearColor]];
1703 [placard insertSubview:background belowSubview:table];
1704 }
1705 }
1706 }
1707 // }}}
1708
1709 // %hook _UIImageWithName() {{{
1710 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1711 if (Debug_)
1712 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1713 if (name == nil)
1714 return nil;
1715
1716 int identifier;
1717 bool packed;
1718
1719 if (_UIPackedImageTableGetIdentifierForName != NULL)
1720 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1721 else if (_UISharedImageNameGetIdentifier != NULL) {
1722 identifier = _UISharedImageNameGetIdentifier(name);
1723 packed = identifier != -1;
1724 } else {
1725 identifier = -1;
1726 packed = false;
1727 }
1728
1729 if (Debug_)
1730 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1731
1732 if (!packed)
1733 return __UIImageWithName(name);
1734 else {
1735 NSNumber *key([NSNumber numberWithInt:identifier]);
1736 UIImage *image([UIImages_ objectForKey:key]);
1737 if (image != nil)
1738 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1739 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1740 image = $getImage$(path);
1741 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1742 if (image != nil)
1743 return image;
1744
1745 image = __UIImageWithName(name);
1746
1747 if (UIDebug_) {
1748 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1749 if (![Manager_ fileExistsAtPath:path])
1750 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1751 }
1752
1753 return image;
1754 }
1755 }
1756 // }}}
1757 // %hook _UIImageWithNameInDomain() {{{
1758 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1759 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1760 UIImage *image([PathImages_ objectForKey:key]);
1761 if (image != nil)
1762 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1763 if (Debug_)
1764 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1765 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1766 image = $getImage$(path);
1767 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1768 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1769 }
1770 // }}}
1771
1772 // %hook GSFontCreateWithName() {{{
1773 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1774 if (Debug_)
1775 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1776 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1777 name = [font UTF8String];
1778 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1779 // size *= [scale floatValue];
1780 return _GSFontCreateWithName(name, traits, size);
1781 }
1782 // }}}
1783
1784 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1785 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1786
1787 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1788
1789 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1790 if (Debug_)
1791 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1792 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1793 if (Debug_)
1794 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1795
1796 if (value) {
1797 NSString *path = [NSString stringWithUTF8String:a1];
1798 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1799 NSString *file = [path substringFromIndex:31];
1800 for (NSString *theme in Themes_) {
1801 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1802 if ([Manager_ fileExistsAtPath:path]) {
1803 strcpy(a1, [path UTF8String]);
1804 continue;
1805 }
1806 }
1807 }
1808 }
1809 return value;
1810 }
1811
1812 static void ChangeWallpaper(
1813 CFNotificationCenterRef center,
1814 void *observer,
1815 CFStringRef name,
1816 const void *object,
1817 CFDictionaryRef info
1818 ) {
1819 if (Debug_)
1820 NSLog(@"WB:Debug:ChangeWallpaper!");
1821
1822 UIImage *image;
1823 if (WallpaperFile_ != nil) {
1824 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1825 if (image != nil)
1826 image = [image autorelease];
1827 } else image = nil;
1828
1829 if (WallpaperImage_ != nil)
1830 [WallpaperImage_ setImage:image];
1831 if (WallpaperPage_ != nil)
1832 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1833
1834 }
1835
1836 #define WBRename(name, sel, imp) \
1837 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
1838
1839 template <typename Type_>
1840 static void msset(Type_ &function, MSImageRef image, const char *name) {
1841 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1842 }
1843
1844 template <typename Type_>
1845 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1846 struct nlist &name(nl[index]);
1847 uintptr_t value(name.n_value);
1848 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1849 value |= 0x00000001;
1850 function = reinterpret_cast<Type_>(value);
1851 }
1852
1853 template <typename Type_>
1854 static void dlset(Type_ &function, const char *name) {
1855 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1856 }
1857
1858 // %hook CGImageReadCreateWithFile() {{{
1859 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1860 if (Debug_)
1861 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1862 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1863 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1864 [pool release];
1865 return value;
1866 }
1867 // }}}
1868
1869 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
1870 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1871 if (style == nil || [style length] == 0)
1872 style = @"font-family: Helvetica; font-size: 12px";
1873 return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
1874 }
1875
1876 static void NSString$drawInRect$withStyle$(NSString *self, SEL _cmd, CGRect rect, NSString *style) {
1877 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1878 if (style == nil || [style length] == 0)
1879 style = @"font-family: Helvetica; font-size: 12px";
1880 return [[WBMarkup sharedMarkup] drawString:self inRect:rect withStyle:style];
1881 }
1882
1883 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
1884 if (style == nil || [style length] == 0)
1885 style = @"font-family: Helvetica; font-size: 12px";
1886 return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width];
1887 }
1888
1889 static void SBInitialize() {
1890 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
1891 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v28@0:4{CGRect={CGSize=ff}{CGSize=ff}}8@24");
1892 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
1893
1894 if (SummerBoard_) {
1895 WBRename(SBApplication, pathForIcon, pathForIcon);
1896 WBRename(SBApplicationIcon, icon, icon);
1897 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1898 }
1899
1900 WBRename(SBBookmarkIcon, icon, icon);
1901 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1902 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1903 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1904 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
1905
1906 WBRename(SBWidgetApplicationIcon, icon, icon);
1907
1908 WBRename(SBDockIconListView, setFrame:, setFrame$);
1909 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
1910
1911 if (kCFCoreFoundationVersionNumber < 600)
1912 WBRename(SBIconLabel, drawRect:, drawRect$);
1913 else
1914 WBRename(SBIconLabel, buildLabelImage, buildLabelImage);
1915
1916 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
1917 WBRename(SBIconLabel, setInDock:, setInDock$);
1918
1919 WBRename(SBIconList, setFrame:, setFrame$);
1920
1921 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
1922 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
1923 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
1924 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
1925
1926 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
1927 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
1928 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
1929
1930 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
1931
1932 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
1933 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
1934 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
1935 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
1936 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
1937 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
1938 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
1939 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
1940 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
1941
1942 if (SummerBoard_)
1943 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
1944 }
1945
1946 MSInitialize {
1947 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1948
1949 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
1950 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
1951
1952 Manager_ = [[NSFileManager defaultManager] retain];
1953 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
1954
1955 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
1956
1957 // Load Settings.plist {{{
1958 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
1959 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
1960 SummerBoard_ = [value boolValue];
1961 if (NSNumber *value = [settings objectForKey:@"Debug"])
1962 Debug_ = [value boolValue];
1963 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
1964 UIDebug_ = [value boolValue];
1965
1966 NSArray *themes([settings objectForKey:@"Themes"]);
1967 if (themes == nil)
1968 if (NSString *theme = [settings objectForKey:@"Theme"])
1969 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
1970 theme, @"Name",
1971 [NSNumber numberWithBool:true], @"Active",
1972 nil]];
1973
1974 if (themes != nil)
1975 for (NSDictionary *theme in themes) {
1976 NSNumber *active([theme objectForKey:@"Active"]);
1977 if (![active boolValue])
1978 continue;
1979
1980 NSString *name([theme objectForKey:@"Name"]);
1981 if (name == nil)
1982 continue;
1983
1984 NSString *theme(nil);
1985
1986 #define testForTheme(format...) \
1987 if (theme == nil) { \
1988 NSString *path = [NSString stringWithFormat:format]; \
1989 if ([Manager_ fileExistsAtPath:path]) { \
1990 [Themes_ addObject:path]; \
1991 continue; \
1992 } \
1993 }
1994
1995 testForTheme(@"/Library/Themes/%@.theme", name)
1996 testForTheme(@"/Library/Themes/%@", name)
1997 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
1998
1999 }
2000 }
2001 // }}}
2002 // Merge Info.plist {{{
2003 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2004
2005 for (NSString *theme in Themes_)
2006 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
2007 for (NSString *key in [info allKeys])
2008 if ([Info_ objectForKey:key] == nil)
2009 [Info_ setObject:[info objectForKey:key] forKey:key];
2010 // }}}
2011
2012 // AudioToolbox {{{
2013 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
2014 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
2015 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
2016 }
2017 // }}}
2018 // GraphicsServices {{{
2019 if (true) {
2020 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
2021 }
2022 // }}}
2023 // ImageIO {{{
2024 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
2025 void *(*CGImageReadCreateWithFile)(NSString *, int);
2026 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
2027 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
2028 }
2029 // }}}
2030 // SpringBoard {{{
2031 if (SpringBoard_) {
2032 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
2033 Papered_ = $getTheme$(Wallpapers_) != nil;
2034 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
2035
2036 CFNotificationCenterAddObserver(
2037 CFNotificationCenterGetDarwinNotifyCenter(),
2038 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
2039 );
2040
2041 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
2042 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
2043 if (MediaPlayer != nil)
2044 [MediaPlayer load];
2045
2046 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
2047 $MPVideoView = objc_getClass("MPVideoView");
2048 }
2049
2050 SBInitialize();
2051 }
2052 // }}}
2053 // UIKit {{{
2054 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
2055 struct nlist nl[6];
2056 memset(nl, 0, sizeof(nl));
2057 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
2058 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
2059 nl[2].n_un.n_name = (char *) "__UIKitBundle";
2060 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
2061 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
2062 nlist(UIKit, nl);
2063
2064 nlset(_UIApplicationImageWithName, nl, 0);
2065 nlset(_UIImageWithNameInDomain, nl, 1);
2066 nlset(_UIKitBundle, nl, 2);
2067 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
2068 nlset(_UISharedImageNameGetIdentifier, nl, 4);
2069
2070 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
2071 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
2072 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
2073 }
2074 // }}}
2075
2076 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
2077 NSError *error(nil);
2078 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
2079 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
2080 nil] error:&error])
2081 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);
2082 }
2083
2084 [pool release];
2085 }