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