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