]> git.saurik.com Git - winterboard.git/blob - Library.mm
a872c5ce841761c0b68519906e7483121ae01747
[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 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1559 if ((self = MSOldCall(style, reuse)) != nil) {
1560 [self setBackgroundColor:[UIColor clearColor]];
1561 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1562 } return self;
1563 }
1564
1565 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1566 if ((self = MSOldCall(style, reuse)) != nil) {
1567 [self setBackgroundColor:[UIColor clearColor]];
1568 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1569 } return self;
1570 }
1571
1572 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1573 if ((self = MSOldCall(style, reuse)) != nil) {
1574 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1575 [_label setBackgroundColor:[UIColor clearColor]];
1576 } return self;
1577 }
1578
1579 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1580 MSOldCall(UITableViewCellSeparatorStyleNone);
1581 }
1582
1583 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1584 if ((self = MSOldCall(frame, style)) != nil) {
1585 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1586 } return self;
1587 }
1588
1589 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1590 MSOldCall();
1591
1592 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1593 if (UIImage *image = $getImage$(path)) {
1594 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1595 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1596 UIView *table;
1597 if (&_transcriptTable != NULL)
1598 table = _transcriptTable;
1599 else if (&_transcriptLayer != NULL)
1600 table = _transcriptLayer;
1601 else
1602 table = nil;
1603
1604 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1605 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1606
1607 if (table == nil)
1608 [placard insertSubview:background atIndex:0];
1609 else {
1610 [table setBackgroundColor:[UIColor clearColor]];
1611 [placard insertSubview:background belowSubview:table];
1612 }
1613 }
1614 }
1615 // }}}
1616
1617 // %hook _UIImageWithName() {{{
1618 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1619 if (Debug_)
1620 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1621 if (name == nil)
1622 return nil;
1623
1624 int identifier;
1625 bool packed;
1626
1627 if (_UIPackedImageTableGetIdentifierForName != NULL)
1628 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1629 else if (_UISharedImageNameGetIdentifier != NULL) {
1630 identifier = _UISharedImageNameGetIdentifier(name);
1631 packed = identifier != -1;
1632 } else {
1633 identifier = -1;
1634 packed = false;
1635 }
1636
1637 if (Debug_)
1638 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1639
1640 if (!packed)
1641 return __UIImageWithName(name);
1642 else {
1643 NSNumber *key([NSNumber numberWithInt:identifier]);
1644 UIImage *image([UIImages_ objectForKey:key]);
1645 if (image != nil)
1646 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1647 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1648 image = $getImage$(path);
1649 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1650 if (image != nil)
1651 return image;
1652
1653 image = __UIImageWithName(name);
1654
1655 if (UIDebug_) {
1656 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1657 if (![Manager_ fileExistsAtPath:path])
1658 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1659 }
1660
1661 return image;
1662 }
1663 }
1664 // }}}
1665 // %hook _UIImageWithNameInDomain() {{{
1666 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1667 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1668 UIImage *image([PathImages_ objectForKey:key]);
1669 if (image != nil)
1670 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1671 if (Debug_)
1672 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1673 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1674 image = $getImage$(path);
1675 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1676 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1677 }
1678 // }}}
1679
1680 // %hook GSFontCreateWithName() {{{
1681 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1682 if (Debug_)
1683 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1684 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1685 name = [font UTF8String];
1686 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1687 // size *= [scale floatValue];
1688 return _GSFontCreateWithName(name, traits, size);
1689 }
1690 // }}}
1691
1692 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1693 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1694
1695 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1696
1697 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1698 if (Debug_)
1699 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1700 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1701 if (Debug_)
1702 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1703
1704 if (value) {
1705 NSString *path = [NSString stringWithUTF8String:a1];
1706 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1707 NSString *file = [path substringFromIndex:31];
1708 for (NSString *theme in Themes_) {
1709 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1710 if ([Manager_ fileExistsAtPath:path]) {
1711 strcpy(a1, [path UTF8String]);
1712 continue;
1713 }
1714 }
1715 }
1716 }
1717 return value;
1718 }
1719
1720 static void ChangeWallpaper(
1721 CFNotificationCenterRef center,
1722 void *observer,
1723 CFStringRef name,
1724 const void *object,
1725 CFDictionaryRef info
1726 ) {
1727 if (Debug_)
1728 NSLog(@"WB:Debug:ChangeWallpaper!");
1729
1730 UIImage *image;
1731 if (WallpaperFile_ != nil) {
1732 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1733 if (image != nil)
1734 image = [image autorelease];
1735 } else image = nil;
1736
1737 if (WallpaperImage_ != nil)
1738 [WallpaperImage_ setImage:image];
1739 if (WallpaperPage_ != nil)
1740 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1741
1742 }
1743
1744 #define WBRename(name, sel, imp) \
1745 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
1746
1747 template <typename Type_>
1748 static void msset(Type_ &function, MSImageRef image, const char *name) {
1749 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1750 }
1751
1752 template <typename Type_>
1753 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1754 struct nlist &name(nl[index]);
1755 uintptr_t value(name.n_value);
1756 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1757 value |= 0x00000001;
1758 function = reinterpret_cast<Type_>(value);
1759 }
1760
1761 template <typename Type_>
1762 static void dlset(Type_ &function, const char *name) {
1763 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1764 }
1765
1766 // %hook CGImageReadCreateWithFile() {{{
1767 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1768 if (Debug_)
1769 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1770 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1771 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1772 [pool release];
1773 return value;
1774 }
1775 // }}}
1776
1777 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
1778 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1779 if (style == nil || [style length] == 0)
1780 style = @"font-family: Helvetica; font-size: 12px";
1781 return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
1782 }
1783
1784 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
1785 if (style == nil || [style length] == 0)
1786 style = @"font-family: Helvetica; font-size: 12px";
1787 return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width];
1788 }
1789
1790 static void SBInitialize() {
1791 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
1792 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
1793
1794 if (SummerBoard_) {
1795 WBRename(SBApplication, pathForIcon, pathForIcon);
1796 WBRename(SBApplicationIcon, icon, icon);
1797 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1798 }
1799
1800 WBRename(SBBookmarkIcon, icon, icon);
1801 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1802 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1803 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1804 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
1805
1806 WBRename(SBWidgetApplicationIcon, icon, icon);
1807
1808 WBRename(SBDockIconListView, setFrame:, setFrame$);
1809 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
1810
1811 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
1812 WBRename(SBIconLabel, setInDock:, setInDock$);
1813
1814 WBRename(SBIconList, setFrame:, setFrame$);
1815
1816 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
1817 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
1818 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
1819 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
1820
1821 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
1822 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
1823 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
1824
1825 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
1826
1827 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
1828 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
1829 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
1830 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
1831 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
1832 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
1833 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
1834 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
1835 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
1836
1837 if (SummerBoard_)
1838 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
1839 }
1840
1841 MSInitialize {
1842 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1843
1844 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
1845 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
1846
1847 Manager_ = [[NSFileManager defaultManager] retain];
1848 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
1849
1850 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
1851
1852 // Load Settings.plist {{{
1853 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
1854 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
1855 SummerBoard_ = [value boolValue];
1856 if (NSNumber *value = [settings objectForKey:@"Debug"])
1857 Debug_ = [value boolValue];
1858 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
1859 UIDebug_ = [value boolValue];
1860
1861 NSArray *themes([settings objectForKey:@"Themes"]);
1862 if (themes == nil)
1863 if (NSString *theme = [settings objectForKey:@"Theme"])
1864 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
1865 theme, @"Name",
1866 [NSNumber numberWithBool:true], @"Active",
1867 nil]];
1868
1869 if (themes != nil)
1870 for (NSDictionary *theme in themes) {
1871 NSNumber *active([theme objectForKey:@"Active"]);
1872 if (![active boolValue])
1873 continue;
1874
1875 NSString *name([theme objectForKey:@"Name"]);
1876 if (name == nil)
1877 continue;
1878
1879 NSString *theme(nil);
1880
1881 #define testForTheme(format...) \
1882 if (theme == nil) { \
1883 NSString *path = [NSString stringWithFormat:format]; \
1884 if ([Manager_ fileExistsAtPath:path]) { \
1885 [Themes_ addObject:path]; \
1886 continue; \
1887 } \
1888 }
1889
1890 testForTheme(@"/Library/Themes/%@.theme", name)
1891 testForTheme(@"/Library/Themes/%@", name)
1892 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
1893
1894 }
1895 }
1896 // }}}
1897 // Merge Info.plist {{{
1898 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1899
1900 for (NSString *theme in Themes_)
1901 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
1902 for (NSString *key in [info allKeys])
1903 if ([Info_ objectForKey:key] == nil)
1904 [Info_ setObject:[info objectForKey:key] forKey:key];
1905 // }}}
1906
1907 // AudioToolbox {{{
1908 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
1909 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
1910 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
1911 }
1912 // }}}
1913 // GraphicsServices {{{
1914 if (true) {
1915 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
1916 }
1917 // }}}
1918 // ImageIO {{{
1919 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
1920 void *(*CGImageReadCreateWithFile)(NSString *, int);
1921 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
1922 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
1923 }
1924 // }}}
1925 // SpringBoard {{{
1926 if (SpringBoard_) {
1927 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
1928 Papered_ = $getTheme$(Wallpapers_) != nil;
1929 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]);
1930
1931 CFNotificationCenterAddObserver(
1932 CFNotificationCenterGetDarwinNotifyCenter(),
1933 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
1934 );
1935
1936 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
1937 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
1938 if (MediaPlayer != nil)
1939 [MediaPlayer load];
1940
1941 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
1942 $MPVideoView = objc_getClass("MPVideoView");
1943 }
1944
1945 SBInitialize();
1946 }
1947 // }}}
1948 // UIKit {{{
1949 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
1950 struct nlist nl[6];
1951 memset(nl, 0, sizeof(nl));
1952 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
1953 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
1954 nl[2].n_un.n_name = (char *) "__UIKitBundle";
1955 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
1956 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
1957 nlist(UIKit, nl);
1958
1959 nlset(_UIApplicationImageWithName, nl, 0);
1960 nlset(_UIImageWithNameInDomain, nl, 1);
1961 nlset(_UIKitBundle, nl, 2);
1962 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
1963 nlset(_UISharedImageNameGetIdentifier, nl, 4);
1964
1965 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
1966 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
1967 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
1968 }
1969 // }}}
1970
1971 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
1972 NSError *error(nil);
1973 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
1974 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
1975 nil] error:&error])
1976 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);
1977 }
1978
1979 [pool release];
1980 }