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