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