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