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