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