]> git.saurik.com Git - winterboard.git/blame_incremental - Library.mm
Even if Scale_ is 1, IsWild_ doesn't have to be 0.
[winterboard.git] / Library.mm
... / ...
CommitLineData
1/* WinterBoard - Theme Manager for the iPhone
2 * Copyright (C) 2008-2014 Jay Freeman (saurik)
3*/
4
5/* GNU Lesser General Public License, Version 3 {{{ */
6/*
7 * WinterBoard is free software: you can redistribute it and/or modify it under
8 * the terms of the GNU Lesser General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * WinterBoard is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 * License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with WinterBoard. If not, see <http://www.gnu.org/licenses/>.
19**/
20/* }}} */
21
22#include <sys/time.h>
23
24struct timeval _ltv;
25bool _itv;
26
27#define _trace() do { \
28 struct timeval _ctv; \
29 gettimeofday(&_ctv, NULL); \
30 if (!_itv) { \
31 _itv = true; \
32 _ltv = _ctv; \
33 } \
34 NSLog(@"%lu.%.6u[%f]:WB:_trace()@%s:%u[%s]\n", \
35 _ctv.tv_sec, _ctv.tv_usec, \
36 (_ctv.tv_sec - _ltv.tv_sec) + (_ctv.tv_usec - _ltv.tv_usec) / 1000000.0, \
37 __FILE__, __LINE__, __FUNCTION__\
38 ); \
39 _ltv = _ctv; \
40} while (false)
41
42#define _transient
43
44#import <CoreFoundation/CoreFoundation.h>
45#import <Foundation/Foundation.h>
46#import <CoreGraphics/CoreGraphics.h>
47#import <ImageIO/CGImageSource.h>
48
49#import <Celestial/AVController.h>
50#import <Celestial/AVItem.h>
51#import <Celestial/AVQueue.h>
52
53#include <substrate.h>
54
55#import <UIKit/UIKit.h>
56
57#import <SpringBoard/SBApplication.h>
58#import <SpringBoard/SBApplicationIcon.h>
59#import <SpringBoard/SBAppWindow.h>
60#import <SpringBoard/SBAwayView.h>
61#import <SpringBoard/SBBookmarkIcon.h>
62#import <SpringBoard/SBButtonBar.h>
63#import <SpringBoard/SBCalendarIconContentsView.h>
64#import <SpringBoard/SBIconController.h>
65#import <SpringBoard/SBIconLabel.h>
66#import <SpringBoard/SBIconList.h>
67#import <SpringBoard/SBIconModel.h>
68#import <SpringBoard/SBImageCache.h>
69// XXX: #import <SpringBoard/SBSearchView.h>
70#import <SpringBoard/SBSearchTableViewCell.h>
71#import <SpringBoard/SBStatusBarContentsView.h>
72#import <SpringBoard/SBStatusBarController.h>
73#import <SpringBoard/SBStatusBarOperatorNameView.h>
74#import <SpringBoard/SBStatusBarTimeView.h>
75#import <SpringBoard/SBUIController.h>
76#import <SpringBoard/SBWidgetApplicationIcon.h>
77
78#import <MobileSMS/mSMSMessageTranscriptController.h>
79
80#import <MediaPlayer/MPMoviePlayerController.h>
81#import <MediaPlayer/MPVideoView.h>
82#import <MediaPlayer/MPVideoView-PlaybackControl.h>
83
84#import <CoreGraphics/CGGeometry.h>
85
86#import <ChatKit/CKMessageCell.h>
87
88#include <sys/sysctl.h>
89
90#include "WBMarkup.h"
91
92static void (*$objc_setAssociatedObject)(id object, void *key, id value, objc_AssociationPolicy policy);
93static id (*$objc_getAssociatedObject)(id object, void *key);
94static void (*$objc_removeAssociatedObjects)(id object);
95
96@protocol WinterBoard
97- (void *) _node;
98@end
99
100Class $MPMoviePlayerController;
101Class $MPVideoView;
102
103MSClassHook(NSBundle)
104MSClassHook(NSString)
105
106MSClassHook(UIImage)
107MSMetaClassHook(UIImage)
108MSClassHook(UINavigationBar)
109MSClassHook(UISharedArtwork)
110MSClassHook(UIToolbar)
111MSClassHook(UIStatusBarTimeItemView)
112MSClassHook(UIWebDocumentView)
113
114MSClassHook(CKBalloonView)
115MSClassHook(CKMessageCell)
116MSClassHook(CKTimestampView)
117MSClassHook(CKTranscriptCell)
118MSClassHook(CKTranscriptController)
119MSClassHook(CKTranscriptHeaderView)
120MSClassHook(CKTranscriptTableView)
121
122MSClassHook(SBApplication)
123MSClassHook(SBApplicationIcon)
124MSClassHook(SBAwayView)
125MSClassHook(SBBookmarkIcon)
126MSClassHook(SBButtonBar)
127MSClassHook(SBCalendarApplicationIcon)
128MSClassHook(SBCalendarIconContentsView)
129MSClassHook(SBDockIconListView)
130MSClassHook(SBIcon)
131MSClassHook(SBIconAccessoryImage)
132MSMetaClassHook(SBIconAccessoryImage)
133MSClassHook(SBIconBadge)
134MSClassHook(SBIconBadgeFactory)
135MSClassHook(SBIconBadgeImage)
136MSClassHook(SBIconContentView)
137MSClassHook(SBIconController)
138MSClassHook(SBIconLabel)
139MSClassHook(SBIconLabelImage)
140MSMetaClassHook(SBIconLabelImage)
141MSClassHook(SBIconLabelImageParameters)
142MSClassHook(SBIconList)
143MSClassHook(SBIconModel)
144MSClassHook(SBIconView)
145MSMetaClassHook(SBIconView)
146//MSClassHook(SBImageCache)
147MSClassHook(SBSearchView)
148MSClassHook(SBSearchTableViewCell)
149MSClassHook(SBSlidingAlertDisplay)
150MSClassHook(SBStatusBarContentsView)
151MSClassHook(SBStatusBarController)
152MSClassHook(SBStatusBarOperatorNameView)
153MSClassHook(SBStatusBarTimeView)
154MSClassHook(SBUIController)
155MSClassHook(SBWallpaperView)
156MSClassHook(SBWidgetApplicationIcon)
157
158extern "C" void WKSetCurrentGraphicsContext(CGContextRef);
159
160static struct MSFixClass { MSFixClass() {
161 $UIWebDocumentView = objc_getClass("UIWebBrowserView") ?: $UIWebDocumentView;
162 $SBIcon = objc_getClass("SBIconView") ?: $SBIcon;
163
164 if ($SBIconList == nil)
165 $SBIconList = objc_getClass("SBIconListView");
166 if ($CKTranscriptController == nil)
167 $CKTranscriptController = objc_getClass("mSMSMessageTranscriptController");
168} } MSFixClass;
169
170static bool IsWild_;
171static bool Four_($SBDockIconListView != nil);
172
173@interface NSObject (wb$SBIconAccessoryImage)
174+ (Class) _imageClassForIcon:(SBIcon *)icon location:(int)location;
175@end
176
177@interface NSDictionary (WinterBoard)
178- (UIColor *) wb$colorForKey:(NSString *)key;
179- (BOOL) wb$boolForKey:(NSString *)key;
180@end
181
182@implementation NSDictionary (WinterBoard)
183
184- (UIColor *) wb$colorForKey:(NSString *)key {
185 NSString *value = [self objectForKey:key];
186 if (value == nil)
187 return nil;
188 /* XXX: incorrect */
189 return nil;
190}
191
192- (BOOL) wb$boolForKey:(NSString *)key {
193 if (NSString *value = [self objectForKey:key])
194 return [value boolValue];
195 return false;
196}
197
198@end
199
200static BOOL (*_GSFontGetUseLegacyFontMetrics)();
201#define $GSFontGetUseLegacyFontMetrics() \
202 (_GSFontGetUseLegacyFontMetrics == NULL ? YES : _GSFontGetUseLegacyFontMetrics())
203
204static bool Debug_ = false;
205static bool UIDebug_ = false;
206static bool Engineer_ = false;
207static bool SummerBoard_ = false;
208static bool SpringBoard_;
209
210static UIImage *(*_UIApplicationImageWithName)(NSString *name);
211static UIImage *(*_UIImageWithNameInDomain)(NSString *name, NSString *domain);
212static UIImage *(*_UIImageWithNameUsingCurrentIdiom)(NSString *name);
213static UIImage *(*_UIImageWithDeviceSpecificName)(NSString *name);
214static NSBundle *(*_UIKitBundle)();
215static bool (*_UIPackedImageTableGetIdentifierForName)(NSString *, int *);
216static int (*_UISharedImageNameGetIdentifier)(NSString *);
217
218static NSMutableDictionary *Images_ = [[NSMutableDictionary alloc] initWithCapacity:64];
219static NSMutableDictionary *Cache_ = [[NSMutableDictionary alloc] initWithCapacity:64];
220static NSMutableDictionary *Strings_ = [[NSMutableDictionary alloc] initWithCapacity:0];
221static NSMutableDictionary *Bundles_ = [[NSMutableDictionary alloc] initWithCapacity:2];
222
223static NSFileManager *Manager_;
224static NSMutableArray *Themes_;
225
226static NSDictionary *English_;
227static NSMutableDictionary *Info_;
228
229// $getTheme$() {{{
230static NSMutableDictionary *Themed_ = [[NSMutableDictionary alloc] initWithCapacity:128];
231
232static unsigned Scale_ = 0;
233
234static unsigned $getScale$(NSString *path) {
235 NSString *name(path);
236
237 #define StripName(strip) \
238 if ([name hasSuffix:@ strip]) \
239 name = [name substringWithRange:NSMakeRange(0, [name length] - sizeof(strip) - 1)];
240
241 StripName(".png");
242 StripName(".jpg");
243 StripName("~iphone");
244 StripName("~ipad");
245
246 return [name hasSuffix:@"@2x"] ? 2 : 1;
247}
248
249static NSArray *$useScale$(NSArray *files, bool use = true) {
250 if (use && Scale_ == 0) {
251 UIScreen *screen([UIScreen mainScreen]);
252 if ([screen respondsToSelector:@selector(scale)])
253 Scale_ = [screen scale];
254 else
255 Scale_ = 1;
256 }
257
258 NSString *idiom(IsWild_ ? @"ipad" : @"iphone");
259
260 NSMutableArray *scaled([NSMutableArray arrayWithCapacity:([files count] * 4)]);
261
262 for (NSString *file in files) {
263 NSString *base([file stringByDeletingPathExtension]);
264 NSString *extension([file pathExtension]);
265
266 if (use) {
267 if (Scale_ == 2) {
268 [scaled addObject:[NSString stringWithFormat:@"%@@2x~%@.%@", base, idiom, extension]];
269 [scaled addObject:[NSString stringWithFormat:@"%@@2x.%@", base, extension]];
270 }
271
272 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
273
274 // if (!IsWild_) <- support old themes
275 [scaled addObject:file];
276 } else if ([base hasSuffix: @"@2x"]) {
277 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
278 [scaled addObject:file];
279
280 // XXX: this actually can't be used, as the person loading the file doesn't realize that the @2x changed
281 /*NSString *rest([base substringWithRange:NSMakeRange(0, [base length] - 3)]);
282 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", rest, idiom, extension]];
283 [scaled addObject:[rest stringByAppendingPathExtension:extension]];*/
284 } else {
285 // XXX: this code isn't really complete
286
287 [scaled addObject:file];
288
289 if ([base hasSuffix:[NSString stringWithFormat:@"~%@", idiom]])
290 [scaled addObject:[[base substringWithRange:NSMakeRange(0, [base length] - 1 - [idiom length])] stringByAppendingPathExtension:extension]];
291 }
292 }
293
294 return scaled;
295}
296
297static NSString *$getTheme$(NSArray *files, NSArray *themes = Themes_) {
298 // XXX: this is not reasonable; OMG
299 id key(files);
300
301 @synchronized (Themed_) {
302 if (NSString *path = [Themed_ objectForKey:key])
303 return reinterpret_cast<id>(path) == [NSNull null] ? nil : path;
304 }
305
306 if (Debug_)
307 NSLog(@"WB:Debug: %@", [files description]);
308
309 NSString *path;
310
311 for (NSString *theme in Themes_)
312 for (NSString *file in files) {
313 path = [NSString stringWithFormat:@"%@/%@", theme, file];
314 if ([Manager_ fileExistsAtPath:path]) {
315 if ([[Manager_ destinationOfSymbolicLinkAtPath:path error:NULL] isEqualToString:@"/"])
316 path = nil;
317 goto set;
318 }
319 }
320
321 path = nil;
322 set:
323
324 @synchronized (Themed_) {
325 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:key];
326 }
327
328 return path;
329}
330// }}}
331// $pathForFile$inBundle$() {{{
332static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool ui, bool use) {
333 NSString *identifier = [bundle bundleIdentifier];
334 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
335
336 if (identifier != nil)
337 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
338 if (NSString *folder = [[bundle bundlePath] lastPathComponent]) {
339 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
340 NSString *base([folder stringByDeletingPathExtension]);
341 if ([base hasSuffix:@"~iphone"])
342 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 7)], [folder pathExtension], file]];
343 if ([base hasSuffix:@"~ipad"])
344 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 5)], [folder pathExtension], file]];
345 }
346 if (ui)
347 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
348
349 #define remapResourceName(oldname, newname) \
350 else if ([file isEqualToString:(oldname)]) \
351 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
352
353 bool summer(SpringBoard_ && SummerBoard_);
354
355 if (identifier == nil);
356 else if ([identifier isEqualToString:@"com.apple.chatkit"])
357 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
358 else if ([identifier isEqualToString:@"com.apple.calculator"])
359 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
360 else if ([identifier isEqualToString:@"com.apple.Maps"] && [file isEqualToString:@"Icon-57@2x.png"])
361 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.Maps/icon.png"]];
362 else if (!summer);
363 remapResourceName(@"FSO_BG.png", @"StatusBar")
364 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
365 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
366
367 [names addObject:[NSString stringWithFormat:@"Fallback/%@", file]];
368
369 if (NSString *path = $getTheme$($useScale$(names, use)))
370 return path;
371
372 return nil;
373}
374// }}}
375
376static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
377 NSString *identifier = [self bundleIdentifier];
378 NSString *path = [self path];
379 NSString *folder = [path lastPathComponent];
380 NSString *dname = [self displayName];
381 NSString *didentifier = [self displayIdentifier];
382
383 if (Debug_)
384 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
385
386 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
387
388 /* XXX: I might need to keep this for backwards compatibility
389 if (identifier != nil)
390 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
391 if (folder != nil)
392 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
393
394 #define testForIcon(Name) \
395 if (NSString *name = Name) \
396 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
397
398 if (![didentifier isEqualToString:identifier])
399 testForIcon(didentifier);
400
401 testForIcon(identifier);
402 testForIcon(dname);
403
404 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
405 testForIcon(@"SMS");
406
407 if (didentifier != nil) {
408 testForIcon([English_ objectForKey:didentifier]);
409
410 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
411 if ([parts count] != 1)
412 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
413 testForIcon([english objectForKey:[parts lastObject]]);
414 }
415
416 if (NSString *path = $getTheme$(names))
417 return path;
418
419 return nil;
420}
421
422// -[NSBundle wb$bundleWithFile] {{{
423@interface NSBundle (WinterBoard)
424+ (NSBundle *) wb$bundleWithFile:(NSString *)path;
425@end
426
427@implementation NSBundle (WinterBoard)
428
429+ (NSBundle *) wb$bundleWithFile:(NSString *)path {
430 path = [path stringByDeletingLastPathComponent];
431 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
432 return nil;
433
434 NSBundle *bundle([Bundles_ objectForKey:path]);
435 if (reinterpret_cast<id>(bundle) == [NSNull null])
436 return nil;
437 else if (bundle == nil) {
438 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
439 bundle = [NSBundle bundleWithPath:path];
440 if (bundle == nil)
441 bundle = [NSBundle wb$bundleWithFile:path];
442 if (Debug_)
443 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
444 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
445 }
446
447 return bundle;
448}
449
450@end
451// }}}
452// -[NSString wb$themedPath] {{{
453@interface NSString (WinterBoard)
454- (NSString *) wb$themedPath;
455@end
456
457@implementation NSString (WinterBoard)
458
459- (NSString *) wb$themedPath {
460 if ([self hasPrefix:@"/Library/Themes/"])
461 return self;
462
463 if (Debug_)
464 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
465
466 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
467 NSString *file([self stringByResolvingSymlinksInPath]);
468 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
469 if ([file hasPrefix:prefix]) {
470 NSUInteger length([prefix length]);
471 if (length != [file length])
472 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false, false))
473 return path;
474 }
475 }
476
477 return self;
478}
479
480@end
481// }}}
482
483void WBLogRect(const char *tag, struct CGRect rect) {
484 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
485}
486
487void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
488 CGRect frame([view frame]);
489 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]);
490 index = 0;
491 for (UIView *child in [view subviews])
492 WBLogHierarchy(child, index++, indent + 1);
493}
494
495UIImage *$cacheForImage$(UIImage *image) {
496 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
497 CGRect rect = {CGPointMake(1, 1), [image size]};
498 CGSize size = {rect.size.width + 2, rect.size.height + 2};
499
500 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
501 CGColorSpaceRelease(space);
502
503 CGContextDrawImage(context, rect, [image CGImage]);
504 CGImageRef ref(CGBitmapContextCreateImage(context));
505 CGContextRelease(context);
506
507 UIImage *cache([UIImage imageWithCGImage:ref]);
508 CGImageRelease(ref);
509
510 return cache;
511}
512
513/*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
514 //if ([name isEqualToString:@"icons"]) return nil;
515 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
516}*/
517
518MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
519 NSString *key([icon displayIdentifier]);
520
521 if (UIImage *image = [icon icon]) {
522 CGSize size = [image size];
523 if (size.width != 59 || size.height != 60) {
524 UIImage *cache($cacheForImage$(image));
525 [Cache_ setObject:cache forKey:key];
526 return;
527 }
528 }
529
530 _SBIconModel$cacheImageForIcon$(self, sel, icon);
531}
532
533MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
534 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
535 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
536
537 NSString *key([icon displayIdentifier]);
538
539 if (UIImage *image = [icon icon]) {
540 CGSize size = [image size];
541 if (size.width != 59 || size.height != 60) {
542 UIImage *cache($cacheForImage$(image));
543 [Cache_ setObject:cache forKey:key];
544 return;
545 }
546 }
547}
548
549MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
550 NSString *key([icon displayIdentifier]);
551 if (UIImage *image = [Cache_ objectForKey:key])
552 return image;
553 else
554 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
555}
556
557MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
558 if (small)
559 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
560 NSString *key([icon displayIdentifier]);
561 if (UIImage *image = [Cache_ objectForKey:key])
562 return image;
563 else
564 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
565}
566
567MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
568 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
569 [self setBackgroundColor:[UIColor clearColor]];
570 for (UIView *child in [self subviews])
571 [child setBackgroundColor:[UIColor clearColor]];
572 } return self;
573}
574
575MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
576 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
577 [self setBackgroundColor:[UIColor clearColor]];
578 } return self;
579}
580
581MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
582 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
583 float inset([self edgeInset]);
584 [[UIColor clearColor] set];
585 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
586 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
587}
588
589MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
590 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
591 if (NSString *path = $pathForIcon$([self application]))
592 return [UIImage imageWithContentsOfFile:path];
593 return _SBApplicationIcon$icon(self, sel);
594}
595
596MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
597 if (type == 2)
598 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
599 if (IsWild_ && false) // XXX: delete this code, it should not be supported
600 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
601 return [UIImage imageWithContentsOfFile:path72];
602 if (NSString *path = $pathForIcon$([self application]))
603 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
604 CGFloat width;
605 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
606 width = [$SBIcon defaultIconImageSize].width;
607 else
608 width = 59;
609 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
610 }
611 }
612 return _SBApplicationIcon$generateIconImage$(self, sel, type);
613}
614
615MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
616 if (Debug_)
617 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
618 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
619 return [UIImage imageWithContentsOfFile:path];
620 return _SBWidgetApplicationIcon$icon(self, sel);
621}
622
623MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
624 if (Debug_)
625 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
626 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
627 return [UIImage imageWithContentsOfFile:path];
628 return _SBBookmarkIcon$icon(self, sel);
629}
630
631MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
632 if (NSString *path = $pathForIcon$(self))
633 return path;
634 return _SBApplication$pathForIcon(self, sel);
635}
636
637static UIImage *CachedImageAtPath(NSString *path) {
638 path = [path stringByResolvingSymlinksInPath];
639 UIImage *image = [Images_ objectForKey:path];
640 if (image != nil)
641 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
642 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
643 if (image != nil)
644 image = [image autorelease];
645 [Images_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
646 return image;
647}
648
649MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
650 NSBundle *bundle = [NSBundle mainBundle];
651 if (Debug_)
652 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
653 if (NSString *path = $pathForFile$inBundle$(name, bundle, false, false))
654 return CachedImageAtPath(path);
655 return __UIApplicationImageWithName(name);
656}
657
658#define WBDelegate(delegate) \
659 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
660 if (Engineer_) \
661 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
662 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
663 return sig; \
664 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
665 return nil; \
666 } \
667\
668 - (void) forwardInvocation:(NSInvocation*)inv { \
669 SEL sel = [inv selector]; \
670 if ([delegate respondsToSelector:sel]) \
671 [inv invokeWithTarget:delegate]; \
672 else \
673 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
674 }
675
676// %hook -[NSBundle pathForResource:ofType:] {{{
677MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
678 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
679 if (Debug_)
680 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
681 if (NSString *path = $pathForFile$inBundle$(file, self, false, false))
682 return path;
683 return MSOldCall(resource, type);
684}
685// }}}
686
687static void $drawLabel$(NSString *label, CGRect rect, NSString *style, NSString *custom) {
688 bool ellipsis(false);
689 CGFloat max = rect.size.width - 11, width;
690 width:
691 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
692
693 if (width > max) {
694 size_t length([label length]);
695 CGFloat spacing((width - max) / (length - 1));
696
697 if (spacing > 1.25) {
698 ellipsis = true;
699 label = [label substringToIndex:(length - 1)];
700 goto width;
701 }
702
703 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
704 }
705
706 if (ellipsis)
707 label = [label stringByAppendingString:@"..."];
708
709 if (custom != nil)
710 style = [style stringByAppendingString:custom];
711
712 CGSize size = [label sizeWithStyle:style forWidth:rect.size.width];
713 [label drawAtPoint:CGPointMake((rect.size.width - size.width) / 2 + rect.origin.x, rect.origin.y) withStyle:style];
714}
715
716static struct WBStringDrawingState {
717 WBStringDrawingState *next_;
718 unsigned count_;
719 NSString *base_;
720 NSString *info_;
721} *stringDrawingState_;
722
723extern "C" CGColorSpaceRef CGContextGetFillColorSpace(CGContextRef);
724extern "C" void CGContextGetFillColor(CGContextRef, CGFloat[]);
725
726static NSString *WBColorMarkup() {
727 CGContextRef context(UIGraphicsGetCurrentContext());
728 //NSLog(@"XXX:1:%p", context);
729 if (context == NULL)
730 return @"";
731
732 CGColorSpaceRef space(CGContextGetFillColorSpace(context));
733 //NSLog(@"XXX:2:%p", space);
734 if (space == NULL)
735 return @"";
736
737 size_t number(CGColorSpaceGetNumberOfComponents(space));
738 //NSLog(@"XXX:3:%u", number);
739 if (number == 0)
740 return @"";
741
742 CGFloat components[number + 1];
743 CGContextGetFillColor(context, components);
744
745 CGFloat r, g, b, a;
746
747 switch (number) {
748 case 1:
749 r = components[0];
750 g = components[0];
751 b = components[0];
752 a = components[1];
753 break;
754
755 case 3:
756 r = components[0];
757 g = components[1];
758 b = components[2];
759 a = components[3];
760 break;
761
762 default:
763 return @"";
764 }
765
766 return [NSString stringWithFormat:@"color: rgba(%g, %g, %g, %g)", r * 255, g * 255, b * 255, a];
767}
768
769extern "C" NSString *NSStringFromCGPoint(CGPoint rect);
770
771MSInstanceMessage6(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode,letterSpacing,includeEmoji, CGPoint, point, CGFloat, width, UIFont *, font, UILineBreakMode, mode, CGFloat, spacing, BOOL, emoji) {
772 //NSLog(@"XXX: @\"%@\" %@ %g \"%@\" %u %g %u", self, NSStringFromCGPoint(point), width, font, mode, spacing, emoji);
773
774 WBStringDrawingState *state(stringDrawingState_);
775 if (state == NULL)
776 return MSOldCall(point, width, font, mode, spacing, emoji);
777
778 if (state->count_ != 0 && --state->count_ == 0)
779 stringDrawingState_ = state->next_;
780 if (state->info_ == nil)
781 return MSOldCall(point, width, font, mode, spacing, emoji);
782
783 NSString *info([Info_ objectForKey:state->info_]);
784 if (info == nil)
785 return MSOldCall(point, width, font, mode, spacing, emoji);
786
787 NSString *base(state->base_ ?: @"");
788 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
789 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
790 return CGSizeZero;
791}
792
793extern "C" NSString *NSStringFromCGRect(CGRect rect);
794
795MSInstanceMessageHook7(CGSize, NSString, _drawInRect,withFont,lineBreakMode,alignment,lineSpacing,includeEmoji,truncationRect, CGRect, rect, UIFont *, font, UILineBreakMode, mode, UITextAlignment, alignment, float, spacing, BOOL, emoji, CGRect, truncation) {
796 //NSLog(@"XXX: @\"%@\" %@ \"%@\" %u %u %g %u %@", self, NSStringFromCGRect(rect), font, mode, alignment, spacing, emoji, NSStringFromCGRect(truncation));
797
798 WBStringDrawingState *state(stringDrawingState_);
799 if (state == NULL)
800 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
801
802 if (state->count_ != 0 && --state->count_ == 0)
803 stringDrawingState_ = state->next_;
804 if (state->info_ == nil)
805 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
806
807 NSString *info([Info_ objectForKey:state->info_]);
808 if (info == nil)
809 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
810
811 NSString *textAlign;
812 switch (alignment) {
813 default:
814 case UITextAlignmentLeft:
815 textAlign = @"left";
816 break;
817 case UITextAlignmentCenter:
818 textAlign = @"center";
819 break;
820 case UITextAlignmentRight:
821 textAlign = @"right";
822 break;
823 }
824
825 NSString *base(state->base_ ?: @"");
826 NSString *extra([NSString stringWithFormat:@"text-align: %@", textAlign]);
827
828 if (true)
829 $drawLabel$(self, rect, [NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], WBColorMarkup(), base], info);
830 else
831 [self drawInRect:rect withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
832
833 return CGSizeZero;
834}
835
836MSInstanceMessage4(CGSize, NSString, sizeWithFont,forWidth,lineBreakMode,letterSpacing, UIFont *, font, CGFloat, width, UILineBreakMode, mode, CGFloat, spacing) {
837 //NSLog(@"XXX: #\"%@\" \"%@\" %g %u %g", self, font, width, mode, spacing);
838
839 WBStringDrawingState *state(stringDrawingState_);
840 if (state == NULL)
841 return MSOldCall(font, width, mode, spacing);
842
843 if (state->count_ != 0 && --state->count_ == 0)
844 stringDrawingState_ = state->next_;
845 if (state->info_ == nil)
846 return MSOldCall(font, width, mode, spacing);
847
848 NSString *info([Info_ objectForKey:state->info_]);
849 if (info == nil)
850 return MSOldCall(font, width, mode, spacing);
851
852 NSString *base(state->base_ ?: @"");
853 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
854 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info] forWidth:width];
855}
856
857MSInstanceMessage1(CGSize, NSString, sizeWithFont, UIFont *, font) {
858 //NSLog(@"XXX: ?\"%@\"", self);
859
860 WBStringDrawingState *state(stringDrawingState_);
861 if (state == NULL)
862 return MSOldCall(font);
863
864 if (state->count_ != 0 && --state->count_ == 0)
865 stringDrawingState_ = state->next_;
866 if (state->info_ == nil)
867 return MSOldCall(font);
868
869 NSString *info([Info_ objectForKey:state->info_]);
870 if (info == nil)
871 return MSOldCall(font);
872
873 NSString *base(state->base_ ?: @"");
874 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), base, info] forWidth:65535];
875}
876
877MSClassMessageHook2(UIImage *, SBIconAccessoryImage, checkoutAccessoryImageForIcon,location, id, icon, int, location) {
878 if ([self _imageClassForIcon:icon location:location] != $SBIconBadgeImage)
879 return MSOldCall(icon, location);
880
881 WBStringDrawingState badgeState = {NULL, 0, @""
882 , @"BadgeStyle"};
883
884 stringDrawingState_ = &badgeState;
885
886 UIImage *image(MSOldCall(icon, location));
887
888 stringDrawingState_ = NULL;
889 return image;
890}
891
892MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
893 WBStringDrawingState badgeState = {NULL, 0, @""
894 , @"BadgeStyle"};
895
896 stringDrawingState_ = &badgeState;
897
898 UIImage *image(MSOldCall(text));
899
900 stringDrawingState_ = NULL;
901 return image;
902}
903
904MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
905 WBStringDrawingState dayState = {NULL, 2, @""
906 // XXX: this is only correct on an iPod dock
907 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
908 , @"CalendarIconDayStyle"};
909
910 WBStringDrawingState wtfState = {&dayState, 1, nil, nil};
911
912 WBStringDrawingState sizeState = {
913 kCFCoreFoundationVersionNumber > 800 ? &wtfState : &dayState
914 , 7, nil, nil};
915
916 WBStringDrawingState dateState = {&sizeState, 2, @""
917 , @"CalendarIconDateStyle"};
918
919 stringDrawingState_ = &dateState;
920
921 UIImage *image(MSOldCall(type));
922
923 stringDrawingState_ = NULL;
924 return image;
925}
926
927MSInstanceMessageHook1(UIImage *, UIStatusBarTimeItemView, contentsImageForStyle, int, style) {
928 WBStringDrawingState timeState = {NULL, 0, @""
929 , @"TimeStyle"};
930
931 stringDrawingState_ = &timeState;
932
933 UIImage *image(MSOldCall(style));
934
935 stringDrawingState_ = NULL;
936 return image;
937}
938
939MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
940 NSBundle *bundle([NSBundle mainBundle]);
941
942 CFLocaleRef locale(CFLocaleCopyCurrent());
943 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
944 CFRelease(locale);
945
946 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
947
948 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
949 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
950 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
951 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
952
953 CFRelease(now);
954
955 CFRelease(formatter);
956
957 NSString *datestyle([@""
958 "font-family: Helvetica; "
959 "font-weight: bold; "
960 "color: #333333; "
961 "alpha: 1.0; "
962 "" stringByAppendingString:(IsWild_
963 ? @"font-size: 54px; "
964 : @"font-size: 39px; "
965 )]);
966
967 NSString *daystyle([@""
968 "font-family: Helvetica; "
969 "font-weight: bold; "
970 "color: white; "
971 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
972 "" stringByAppendingString:(IsWild_
973 ? @"font-size: 11px; "
974 : @"font-size: 9px; "
975 )]);
976
977 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
978 datestyle = [datestyle stringByAppendingString:style];
979 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
980 daystyle = [daystyle stringByAppendingString:style];
981
982 CGFloat width([self bounds].size.width);
983 float leeway(10);
984 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
985 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
986
987 unsigned base0(IsWild_ ? 89 : 70);
988 if ($GSFontGetUseLegacyFontMetrics())
989 base0 = base0 + 1;
990 unsigned base1(IsWild_ ? 18 : 16);
991
992 if (Four_) {
993 ++base0;
994 ++base1;
995 }
996
997 [(NSString *)date drawAtPoint:CGPointMake(
998 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
999 ) withStyle:datestyle];
1000
1001 [(NSString *)day drawAtPoint:CGPointMake(
1002 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
1003 ) withStyle:daystyle];
1004
1005 CFRelease(date);
1006 CFRelease(day);
1007}
1008
1009// %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
1010void $setBarStyle$_(NSString *name, int &style) {
1011 if (Debug_)
1012 NSLog(@"WB:Debug:%@Style:%d", name, style);
1013 NSNumber *number = nil;
1014 if (number == nil)
1015 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
1016 if (number == nil)
1017 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
1018 if (number != nil) {
1019 style = [number intValue];
1020 if (Debug_)
1021 NSLog(@"WB:Debug:%@Style=%d", name, style);
1022 }
1023}
1024
1025MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
1026 $setBarStyle$_(@"Toolbar", style);
1027 return MSOldCall(style);
1028}
1029
1030MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
1031 $setBarStyle$_(@"NavigationBar", style);
1032 return MSOldCall(style);
1033}
1034// }}}
1035
1036MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
1037 [[self superview] setBackgroundColor:[UIColor clearColor]];
1038 _SBButtonBar$didMoveToSuperview(self, sel);
1039}
1040
1041MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
1042 [[self superview] setBackgroundColor:[UIColor clearColor]];
1043 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
1044}
1045
1046static NSArray *Wallpapers_;
1047static bool Papered_;
1048static bool Docked_;
1049static bool SMSBackgrounded_;
1050static NSString *WallpaperFile_;
1051static UIImageView *WallpaperImage_;
1052static UIWebDocumentView *WallpaperPage_;
1053static NSURL *WallpaperURL_;
1054
1055#define _release(object) \
1056 do if (object != nil) { \
1057 [object release]; \
1058 object = nil; \
1059 } while (false)
1060
1061static UIImage *$getImage$(NSString *path) {
1062 UIImage *image([UIImage imageWithContentsOfFile:path]);
1063
1064 unsigned scale($getScale$(path));
1065 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
1066 [image setScale:scale];
1067
1068 return image;
1069}
1070
1071template <typename Original_, typename Modified_>
1072_finline UIImage *WBCacheImage(const Original_ &original, const Modified_ &modified, NSString *key) {
1073 UIImage *image([Images_ objectForKey:key]);
1074 if (image != nil)
1075 return reinterpret_cast<id>(image) == [NSNull null] ? original() : image;
1076 if (NSString *path = modified())
1077 image = $getImage$(path);
1078 [Images_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1079 return image == nil ? original() : image;
1080}
1081
1082static UIImage *$getDefaultDesktopImage$() {
1083 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
1084 return $getImage$(path);
1085 return nil;
1086}
1087
1088MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
1089 return $getDefaultDesktopImage$() ?: MSOldCall();
1090}
1091
1092MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
1093 return $getDefaultDesktopImage$() ?: MSOldCall();
1094}
1095
1096MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
1097 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
1098 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
1099 if (UIImage *image = $getDefaultDesktopImage$()) {
1100 [self setImage:image];
1101 return;
1102 }
1103
1104 break;
1105 }
1106
1107 MSOldCall();
1108}
1109
1110// %hook -[SBUIController init] {{{
1111MSInstanceMessageHook0(id, SBUIController, init) {
1112 self = MSOldCall();
1113 if (self == nil)
1114 return nil;
1115
1116 NSString *paper($getTheme$(Wallpapers_));
1117 if (paper != nil)
1118 paper = [paper stringByDeletingLastPathComponent];
1119
1120 {
1121 size_t size;
1122 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
1123 char *machine = new char[size];
1124
1125 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
1126 perror("sysctlbyname(\"hw.machine\", ?)");
1127 delete [] machine;
1128 machine = NULL;
1129 }
1130
1131 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
1132 }
1133
1134 if (Debug_)
1135 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
1136
1137 if (paper != nil) {
1138 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
1139 if (&_wallpaperView != NULL) {
1140 [_wallpaperView removeFromSuperview];
1141 [_wallpaperView release];
1142 _wallpaperView = nil;
1143 }
1144 }
1145
1146 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
1147 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
1148
1149 UIView **player;
1150 if (&_contentLayer != NULL)
1151 player = &_contentLayer;
1152 else if (&_contentView != NULL)
1153 player = &_contentView;
1154 else
1155 player = NULL;
1156 UIView *layer(player == NULL ? nil : *player);
1157
1158 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
1159 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
1160 [window setContentView:content];
1161
1162 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
1163 [window setBackgroundColor:[_window backgroundColor]];
1164 [_window setBackgroundColor:[UIColor clearColor]];
1165
1166 [window setLevel:-1000];
1167 [window setHidden:NO];
1168
1169 /*if (player != NULL)
1170 *player = content;*/
1171
1172 [content setBackgroundColor:[layer backgroundColor]];
1173 [layer setBackgroundColor:[UIColor clearColor]];
1174
1175 UIView *indirect;
1176 if (!SummerBoard_ || !IsWild_)
1177 indirect = content;
1178 else {
1179 CGRect bounds([content bounds]);
1180 bounds.origin.y = -30;
1181 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
1182 [content addSubview:indirect];
1183 [indirect zoomToScale:2.4];
1184 }
1185
1186 _release(WallpaperFile_);
1187 _release(WallpaperImage_);
1188 _release(WallpaperPage_);
1189 _release(WallpaperURL_);
1190
1191 if (paper != nil) {
1192 NSArray *themes([NSArray arrayWithObject:paper]);
1193
1194 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1195#if UseAVController
1196 NSError *error;
1197
1198 static AVController *controller_(nil);
1199 if (controller_ == nil) {
1200 AVQueue *queue([AVQueue avQueue]);
1201 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1202 }
1203
1204 AVQueue *queue([controller_ queue]);
1205
1206 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1207 [controller_ setLayer:[video _layer]];
1208
1209 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1210 [queue appendItem:item error:&error];
1211
1212 [controller_ play:&error];
1213#elif UseMPMoviePlayerController
1214 NSURL *url([NSURL fileURLWithPath:path]);
1215 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1216 controller.movieControlMode = MPMovieControlModeHidden;
1217 [controller play];
1218#else
1219 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1220 [video setMovieWithPath:path];
1221 [video setRepeatMode:1];
1222 [video setRepeatGap:-1];
1223 [video playFromBeginning];;
1224#endif
1225
1226 [indirect addSubview:video];
1227 }
1228
1229 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1230 if (UIImage *image = $getImage$(path)) {
1231 WallpaperFile_ = [path retain];
1232 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1233 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1234 [WallpaperImage_ setAlpha:[number floatValue]];
1235 [indirect addSubview:WallpaperImage_];
1236 }
1237 }
1238
1239 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1240 CGRect bounds = [indirect bounds];
1241
1242 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1243 [view setAutoresizes:true];
1244
1245 WallpaperPage_ = [view retain];
1246 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1247
1248 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1249
1250 [view setBackgroundColor:[UIColor clearColor]];
1251 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1252 [view setDrawsBackground:NO];
1253 [[view webView] setDrawsBackground:NO];
1254
1255 [indirect addSubview:view];
1256 }
1257 }
1258
1259 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1260 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1261 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1262 if ([Manager_ fileExistsAtPath:html]) {
1263 CGRect bounds = [indirect bounds];
1264
1265 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1266 [view setAutoresizes:true];
1267
1268 NSURL *url = [NSURL fileURLWithPath:html];
1269 [view loadRequest:[NSURLRequest requestWithURL:url]];
1270
1271 [view setBackgroundColor:[UIColor clearColor]];
1272 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1273 [view setDrawsBackground:NO];
1274 [[view webView] setDrawsBackground:NO];
1275
1276 [indirect addSubview:view];
1277 }
1278 }
1279
1280 return self;
1281}
1282// }}}
1283
1284MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1285 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1286 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1287
1288 if (path != nil && _backgroundView != nil)
1289 path = nil;
1290
1291 _SBAwayView$updateDesktopImage$(self, sel, image);
1292
1293 if (path != nil) {
1294 CGRect bounds = [self bounds];
1295
1296 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1297 [view setAutoresizes:true];
1298
1299 if (WallpaperPage_ != nil)
1300 [WallpaperPage_ release];
1301 WallpaperPage_ = [view retain];
1302
1303 if (WallpaperURL_ != nil)
1304 [WallpaperURL_ release];
1305 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1306
1307 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1308
1309 [[view webView] setDrawsBackground:false];
1310 [view setBackgroundColor:[UIColor clearColor]];
1311
1312 [self insertSubview:view aboveSubview:_backgroundView];
1313
1314 if ($objc_setAssociatedObject != NULL)
1315 $objc_setAssociatedObject(self, @selector(wb$widgetView), view, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1316 }
1317}
1318
1319MSHook(void, SBAwayView$_addSubview$positioned$relativeTo$, SBAwayView *self, SEL sel, UIView *view, int positioned, UIView *relative) {
1320 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1321 UIView *&_chargingView(MSHookIvar<UIView *>(self, "_chargingView"));
1322 if (&_chargingView != NULL)
1323 if (positioned == -2 && (relative == _backgroundView && _chargingView == nil || relative == _chargingView))
1324 if ($objc_getAssociatedObject != NULL)
1325 if (UIView *widget = $objc_getAssociatedObject(self, @selector(wb$widgetView)))
1326 relative = widget;
1327 return _SBAwayView$_addSubview$positioned$relativeTo$(self, sel, view, positioned, relative);
1328}
1329
1330/*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1331extern "C" CGColorRef CGGStateGetFillColor(void *);
1332extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1333extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1334
1335/* WBTimeLabel {{{ */
1336@interface WBTimeLabel : NSProxy {
1337 NSString *time_;
1338 _transient SBStatusBarTimeView *view_;
1339}
1340
1341- (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1342
1343@end
1344
1345@implementation WBTimeLabel
1346
1347- (void) dealloc {
1348 [time_ release];
1349 [super dealloc];
1350}
1351
1352- (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1353 time_ = [time retain];
1354 view_ = view;
1355 return self;
1356}
1357
1358- (NSString *) description {
1359 return time_;
1360}
1361
1362WBDelegate(time_)
1363
1364- (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1365 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1366 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1367
1368 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1369 "font-family: Helvetica; "
1370 "font-weight: bold; "
1371 "font-size: 14px; "
1372 "color: %@; "
1373 "%@", _mode ? @"white" : @"black", custom]];
1374
1375 return CGSizeZero;
1376 }
1377
1378 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1379}
1380
1381@end
1382/* }}} */
1383/* WBBadgeLabel {{{ */
1384@interface WBBadgeLabel : NSProxy {
1385 NSString *badge_;
1386}
1387
1388- (id) initWithBadge:(NSString *)badge;
1389- (NSString *) description;
1390
1391@end
1392
1393@implementation WBBadgeLabel
1394
1395- (void) dealloc {
1396 [badge_ release];
1397 [super dealloc];
1398}
1399
1400- (id) initWithBadge:(NSString *)badge {
1401 badge_ = [badge retain];
1402 return self;
1403}
1404
1405- (NSString *) description {
1406 return [badge_ description];
1407}
1408
1409WBDelegate(badge_)
1410
1411- (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1412 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1413 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1414 "font-family: Helvetica; "
1415 "font-weight: bold; "
1416 "font-size: 17px; "
1417 "color: white; "
1418 "%@", custom]];
1419
1420 return CGSizeZero;
1421 }
1422
1423 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1424}
1425
1426@end
1427/* }}} */
1428
1429// IconAlpha {{{
1430MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1431 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1432 alpha = [number floatValue];
1433 return MSOldCall(alpha);
1434}
1435
1436MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1437 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1438 alpha = [number floatValue];
1439 return MSOldCall(alpha);
1440}
1441
1442MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1443 if ((self = MSOldCall()) != nil) {
1444 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1445 // XXX: note: this is overridden above, which is silly
1446 float alpha([number floatValue]);
1447 if ([self respondsToSelector:@selector(setIconImageAlpha:)])
1448 [self setIconImageAlpha:alpha];
1449 if ([self respondsToSelector:@selector(setIconLabelAlpha:)])
1450 [self setIconLabelAlpha:alpha];
1451 if ([self respondsToSelector:@selector(setAlpha:)])
1452 [self setAlpha:alpha];
1453 }
1454 } return self;
1455}
1456
1457MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1458 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1459 alpha = [number floatValue];
1460 return MSOldCall(alpha);
1461}
1462// }}}
1463
1464MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1465 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1466 id &_badge(MSHookIvar<id>(self, "_badge"));
1467 if (_badge != nil)
1468 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1469 _badge = label;
1470 } return self;
1471}
1472
1473void SBStatusBarController$setStatusBarMode(int &mode) {
1474 if (Debug_)
1475 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1476 if (mode < 100) // 104:hidden 105:glowing
1477 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1478 mode = [number intValue];
1479}
1480
1481/*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1482 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1483 SBStatusBarController$setStatusBarMode(mode);
1484 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1485}*/
1486
1487MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1488 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1489 SBStatusBarController$setStatusBarMode(mode);
1490 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1491}
1492
1493MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int fenceID, int animation, double startTime) {
1494 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1495 SBStatusBarController$setStatusBarMode(mode);
1496 //NSLog(@"mode=%u", mode);
1497 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1498}
1499
1500/*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1501 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1502 mode = [number intValue];
1503 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1504}*/
1505
1506MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1507 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1508 if (Debug_)
1509 NSLog(@"operatorNameStyle= %@", style);
1510 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1511 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1512 return style;
1513}
1514
1515MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1516 if (Debug_)
1517 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1518 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1519}
1520
1521// XXX: replace this with [SBStatusBarTimeView tile]
1522MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1523 id &_time(MSHookIvar<id>(self, "_time"));
1524 if (_time != nil && [_time class] != [WBTimeLabel class])
1525 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1526 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1527}
1528
1529@interface UIView (WinterBoard)
1530- (bool) wb$isWBImageView;
1531- (void) wb$logHierarchy;
1532- (void) wb$setBackgroundColor:(UIColor *)color;
1533@end
1534
1535@implementation UIView (WinterBoard)
1536
1537- (bool) wb$isWBImageView {
1538 return false;
1539}
1540
1541- (void) wb$logHierarchy {
1542 WBLogHierarchy(self);
1543}
1544
1545- (void) wb$setBackgroundColor:(UIColor *)color {
1546 [self setBackgroundColor:color];
1547 for (UIView *child in [self subviews])
1548 [child wb$setBackgroundColor:color];
1549}
1550
1551@end
1552
1553@interface WBImageView : UIImageView {
1554}
1555
1556- (bool) wb$isWBImageView;
1557- (void) wb$updateFrame;
1558@end
1559
1560@implementation WBImageView
1561
1562- (bool) wb$isWBImageView {
1563 return true;
1564}
1565
1566- (void) wb$updateFrame {
1567 CGRect frame([self frame]);
1568 frame.origin.y = 0;
1569
1570 for (UIView *view(self); ; ) {
1571 view = [view superview];
1572 if (view == nil)
1573 break;
1574 frame.origin.y -= [view frame].origin.y;
1575 }
1576
1577 [self setFrame:frame];
1578}
1579
1580@end
1581
1582static void SBIconList$updateFrames$(SBIconList *self) {
1583 NSArray *subviews([self subviews]);
1584 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1585 if (view != nil && [view wb$isWBImageView])
1586 [view wb$updateFrame];
1587}
1588
1589MSHook(void, SBIconList$didMoveToSuperview, SBIconList *self, SEL sel) {
1590 SBIconList$updateFrames$(self);
1591 _SBIconList$didMoveToSuperview(self, sel);
1592}
1593
1594MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1595 SBIconList$updateFrames$(self);
1596 _SBIconList$setFrame$(self, sel, frame);
1597}
1598
1599static void $addPerPageView$(unsigned i, UIView *list) {
1600 NSString *path($getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]]));
1601 if (path == nil)
1602 return;
1603
1604 NSArray *subviews([list subviews]);
1605
1606 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1607 if (view == nil || ![view wb$isWBImageView]) {
1608 view = [[[WBImageView alloc] init] autorelease];
1609 [list insertSubview:view atIndex:0];
1610 }
1611
1612 UIImage *image([UIImage imageWithContentsOfFile:path]);
1613
1614 CGRect frame([view frame]);
1615 frame.size = [image size];
1616 [view setFrame:frame];
1617
1618 [view setImage:image];
1619 [view wb$updateFrame];
1620}
1621
1622static void $addPerPageViews$(NSArray *lists) {
1623 for (unsigned i(0), e([lists count]); i != e; ++i)
1624 $addPerPageView$(i, [lists objectAtIndex:i]);
1625}
1626
1627MSInstanceMessageHook0(void, SBIconController, updateNumberOfRootIconLists) {
1628 NSArray *&_rootIconLists(MSHookIvar<NSArray *>(self, "_rootIconLists"));
1629 $addPerPageViews$(_rootIconLists);
1630 return MSOldCall();
1631}
1632
1633MSInstanceMessageHook0(void, SBIconContentView, layoutSubviews) {
1634 MSOldCall();
1635
1636 if (SBIconController *controller = [$SBIconController sharedInstance]) {
1637 UIView *&_dockContainerView(MSHookIvar<UIView *>(controller, "_dockContainerView"));
1638 if (&_dockContainerView != NULL)
1639 [[_dockContainerView superview] bringSubviewToFront:_dockContainerView];
1640 }
1641}
1642
1643MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1644 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1645 $addPerPageViews$([_iconModel iconLists]);
1646 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1647}
1648
1649MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1650 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1651 if (self != nil)
1652 [self setClipsToBounds:NO];
1653 return self;
1654}
1655
1656MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1657 static bool gssc(false);
1658 if (!gssc) {
1659 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1660 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1661 gssc = true;
1662
1663 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1664 [Info_ setObject:[NSNumber numberWithBool:(
1665 !Papered_ ||
1666 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1667 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1668 )] forKey:@"UndockedIconLabels"];
1669 }
1670
1671 id &_label(MSHookIvar<id>(self, "_label"));
1672 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1673 docked = true;
1674
1675 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1676 [_label setInDock:docked];
1677
1678 _SBIconLabel$setInDock$(self, sel, docked);
1679 [self setNeedsDisplay];
1680}
1681
1682MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1683 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1684}
1685
1686MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1687 _SBDockIconListView$setFrame$(self, sel, frame);
1688}
1689
1690// %hook -[NSBundle localizedStringForKey:value:table:] {{{
1691MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1692 NSString *identifier = [self bundleIdentifier];
1693 NSLocale *locale = [NSLocale currentLocale];
1694 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1695 if (Debug_)
1696 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1697 NSString *file = table == nil ? @"Localizable" : table;
1698 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1699 NSDictionary *strings;
1700 if ((strings = [Strings_ objectForKey:name]) != nil) {
1701 if (static_cast<id>(strings) != [NSNull null]) strings:
1702 if (NSString *value = [strings objectForKey:key])
1703 return value;
1704 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1705 language, file
1706 ], self, false, false)) {
1707 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1708 [Strings_ setObject:[strings autorelease] forKey:name];
1709 goto strings;
1710 } else goto null;
1711 } else null:
1712 [Strings_ setObject:[NSNull null] forKey:name];
1713 return MSOldCall(key, value, table);
1714}
1715// }}}
1716// %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1717MSClassHook(WebCoreFrameBridge)
1718
1719MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1720 if (node == nil)
1721 return CGSizeZero;
1722 void **core(reinterpret_cast<void **>([node _node]));
1723 if (core == NULL || core[6] == NULL)
1724 return CGSizeZero;
1725 return MSOldCall(node, width);
1726}
1727// }}}
1728
1729MSInstanceMessage1(void, SBIconLabel, drawRect, CGRect, rect) {
1730 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1731
1732 int docked;
1733 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1734 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1735
1736 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1737
1738 NSString *style = [NSString stringWithFormat:@""
1739 "font-family: Helvetica; "
1740 "font-weight: bold; "
1741 "color: %@; %@"
1742 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1743 ? @"font-size: 12px; "
1744 : @"font-size: 11px; "
1745 )];
1746
1747 if (IsWild_)
1748 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1749 else if (docked)
1750 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1751
1752 NSString *custom([Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")]);
1753
1754 $drawLabel$(label, [self bounds], style, custom);
1755}
1756
1757MSInstanceMessage0(CGImageRef, SBIconLabel, buildLabelImage) {
1758 bool docked((MSHookIvar<unsigned>(self, "_inDock") & 0x2) != 0);
1759
1760 WBStringDrawingState labelState = {NULL, 0, @""
1761 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1762
1763 stringDrawingState_ = &labelState;
1764
1765 //NSLog(@"XXX: +");
1766 CGImageRef image(MSOldCall());
1767 //NSLog(@"XXX: -");
1768
1769 stringDrawingState_ = NULL;
1770 return image;
1771}
1772
1773static bool wb$inDock(id parameters) {
1774 return [$objc_getAssociatedObject(parameters, @selector(wb$inDock)) boolValue];
1775}
1776
1777MSInstanceMessage0(NSUInteger, SBIconLabelImageParameters, hash) {
1778 return MSOldCall() + (wb$inDock(self) ? 0xdeadbeef : 0xd15ea5e);
1779}
1780
1781MSClassMessage2(id, SBIconView, _labelImageParametersForIcon,location, id, icon, int, location) {
1782 if (id parameters = MSOldCall(icon, location)) {
1783 $objc_setAssociatedObject(parameters, @selector(wb$inDock), [NSNumber numberWithBool:(location == 1)], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1784 return parameters;
1785 } return nil;
1786}
1787
1788MSInstanceMessage0(id, SBIconView, _labelImageParameters) {
1789 if (id parameters = MSOldCall()) {
1790 int &location(MSHookIvar<int>(self, "_iconLocation"));
1791 if (&location != NULL)
1792 $objc_setAssociatedObject(parameters, @selector(wb$inDock), [NSNumber numberWithBool:(location == 3)], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1793 return parameters;
1794 } return nil;
1795}
1796
1797MSClassMessage1(UIImage *, SBIconLabelImage, _drawLabelImageForParameters, id, parameters) {
1798 bool docked(wb$inDock(parameters));
1799
1800 WBStringDrawingState labelState = {NULL, 0, @""
1801 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1802
1803 stringDrawingState_ = &labelState;
1804
1805 //NSLog(@"XXX: +");
1806 UIImage *image(MSOldCall(parameters));
1807 //NSLog(@"XXX: -");
1808
1809 stringDrawingState_ = NULL;
1810 return image;
1811}
1812
1813// ChatKit {{{
1814MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1815 if ((self = MSOldCall(frame, delegate)) != nil) {
1816 [self setBackgroundColor:[UIColor clearColor]];
1817 } return self;
1818}
1819
1820MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1821 return SMSBackgrounded_ ? NO : MSOldCall();
1822}
1823
1824MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1825 [self wb$setBackgroundColor:[UIColor clearColor]];
1826 return MSOldCall();
1827}
1828
1829MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1830 MSOldCall(balloon);
1831 [balloon setBackgroundColor:[UIColor clearColor]];
1832}
1833
1834MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1835 MSOldCall([UIColor clearColor]);
1836 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1837}
1838
1839// iOS >= 5.0
1840MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1841 if ((self = MSOldCall(style, reuse)) != nil) {
1842 [self setBackgroundColor:[UIColor clearColor]];
1843 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1844 } return self;
1845}
1846
1847// iOS << 5.0
1848MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1849 if ((self = MSOldCall(style, reuse)) != nil) {
1850 [self setBackgroundColor:[UIColor clearColor]];
1851 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1852 } return self;
1853}
1854
1855MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1856 if ((self = MSOldCall(style, reuse)) != nil) {
1857 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1858 [_label setBackgroundColor:[UIColor clearColor]];
1859 } return self;
1860}
1861
1862MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1863 MSOldCall(UITableViewCellSeparatorStyleNone);
1864}
1865
1866MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1867 if ((self = MSOldCall(frame, style)) != nil) {
1868 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1869 } return self;
1870}
1871
1872MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1873 MSOldCall();
1874
1875 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1876 if (UIImage *image = $getImage$(path)) {
1877 SMSBackgrounded_ = true;
1878
1879 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1880 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1881 UIView *table;
1882 if (&_transcriptTable != NULL)
1883 table = _transcriptTable;
1884 else if (&_transcriptLayer != NULL)
1885 table = _transcriptLayer;
1886 else
1887 table = nil;
1888
1889 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1890 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1891
1892 if (table == nil)
1893 [placard insertSubview:background atIndex:0];
1894 else {
1895 [table setBackgroundColor:[UIColor clearColor]];
1896 [placard insertSubview:background belowSubview:table];
1897 }
1898 }
1899}
1900// }}}
1901
1902template <typename Original_>
1903static UIImage *WBCacheUIImage(const Original_ &original, NSString *name, NSString *key) {
1904 if ([name rangeOfString:@"."].location == NSNotFound)
1905 name = [name stringByAppendingString:@".png"];
1906 UIImage *image(WBCacheImage(original, [=](){ return $pathForFile$inBundle$(name, _UIKitBundle(), true, true); }, key));
1907 if (image != nil && UIDebug_) {
1908 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1909 if (![Manager_ fileExistsAtPath:path])
1910 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1911 } return image;
1912}
1913
1914// %hook _UIImageWithName() {{{
1915MSHook(UIImage *, _UIImageWithName, NSString *name) {
1916 if (name == nil)
1917 return nil;
1918 if (Debug_)
1919 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1920 return WBCacheUIImage(
1921 [=](){ return __UIImageWithName(name); },
1922 name, [NSString stringWithFormat:@"I:%@", name]);
1923}
1924// }}}
1925// %hook _UIImageWithNameInDomain() {{{
1926MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1927 if (Debug_)
1928 NSLog(@"WB:Debug: _UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1929 return WBCacheImage(
1930 [=](){ return __UIImageWithNameInDomain(name, domain); },
1931 [=](){ return $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])); },
1932 [NSString stringWithFormat:@"D:%zu:%@%@", size_t([domain length]), domain, name]);
1933}
1934// }}}
1935// %hook _UIImageWithDeviceUsingCurrentIdiom() {{{
1936MSHook(UIImage *, _UIImageWithNameUsingCurrentIdiom, NSString *name) {
1937 if (Debug_)
1938 NSLog(@"WB:Debug: _UIImageWithNameUsingCurrentIdiom(\"%@\")", name);
1939 return WBCacheUIImage(
1940 [=](){ return __UIImageWithNameUsingCurrentIdiom(name); },
1941 name, [NSString stringWithFormat:@"I:%@", name]);
1942}
1943// }}}
1944// %hook _UIImageWithDeviceSpecificName() {{{
1945MSHook(UIImage *, _UIImageWithDeviceSpecificName, NSString *name) {
1946 if (Debug_)
1947 NSLog(@"WB:Debug: _UIImageWithDeviceSpecificName(\"%@\")", name);
1948 return WBCacheUIImage(
1949 [=](){ return __UIImageWithDeviceSpecificName(name); },
1950 name, [NSString stringWithFormat:@"S:%@", name]);
1951}
1952// }}}
1953
1954// %hook GSFontCreateWithName() {{{
1955MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1956 if (Debug_)
1957 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1958 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1959 name = [font UTF8String];
1960 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1961 // size *= [scale floatValue];
1962 return _GSFontCreateWithName(name, traits, size);
1963}
1964// }}}
1965
1966#define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1967
1968static bool GetFileNameForThisAction$(bool value, unsigned long a0, char *a1, unsigned long a2, bool &a3) {
1969 if (Debug_)
1970 NSLog(@"WB:Debug:GetFileNameForThisAction(%lu, %s, %lu, %u) = %u", a0, value ? a1 : NULL, a2, a3, value);
1971
1972 if (value) {
1973 NSString *path = [NSString stringWithUTF8String:a1];
1974 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1975 NSString *file = [path substringFromIndex:31];
1976 for (NSString *theme in Themes_) {
1977 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1978 if ([Manager_ fileExistsAtPath:path]) {
1979 strcpy(a1, [path UTF8String]);
1980 break;
1981 }
1982 }
1983 }
1984 }
1985 return value;
1986}
1987
1988MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a3) {
1989 bool value(__Z24GetFileNameForThisActionmPcRb(a0, a1, a3));
1990 return GetFileNameForThisAction$(value, a0, a1, 0, a3);
1991}
1992
1993MSHook(bool, _Z24GetFileNameForThisActionmPcmRb, unsigned long a0, char *a1, unsigned long a2, bool &a3) {
1994 bool value(__Z24GetFileNameForThisActionmPcmRb(a0, a1, a2, a3));
1995 return GetFileNameForThisAction$(value, a0, a1, a2, a3);
1996}
1997
1998static void ChangeWallpaper(
1999 CFNotificationCenterRef center,
2000 void *observer,
2001 CFStringRef name,
2002 const void *object,
2003 CFDictionaryRef info
2004) {
2005 if (Debug_)
2006 NSLog(@"WB:Debug:ChangeWallpaper!");
2007
2008 UIImage *image;
2009 if (WallpaperFile_ != nil) {
2010 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
2011 if (image != nil)
2012 image = [image autorelease];
2013 } else image = nil;
2014
2015 if (WallpaperImage_ != nil)
2016 [WallpaperImage_ setImage:image];
2017 if (WallpaperPage_ != nil)
2018 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
2019
2020}
2021
2022MSHook(NSArray *, CPBitmapCreateImagesFromPath, NSString *path, NSDictionary **names, void *arg2, void *arg3) {
2023 NSArray *images(_CPBitmapCreateImagesFromPath(path, names, arg2, arg3));
2024 if (images != NULL && *names != nil && CFGetTypeID((CFTypeRef) *names) == CFDictionaryGetTypeID()) {
2025 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:path]) {
2026 NSMutableArray *copy([images mutableCopy]);
2027 [images release];
2028 images = copy;
2029
2030 NSString *file([path stringByResolvingSymlinksInPath]);
2031 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
2032 if ([file hasPrefix:prefix]) {
2033 NSUInteger length([prefix length]);
2034 if (length != [file length]) {
2035 NSEnumerator *enumerator([*names keyEnumerator]);
2036 while (NSString *name = [enumerator nextObject]) {
2037 NSString *png([name stringByAppendingString:@".png"]);
2038 if (NSString *themed = $pathForFile$inBundle$(png, bundle, false, true)) {
2039 NSUInteger index([[*names objectForKey:name] intValue]);
2040 UIImage *image($getImage$(themed));
2041 CGImageRef cg([image CGImage]);
2042 [copy replaceObjectAtIndex:index withObject:(id)cg];
2043 }
2044 }
2045 }
2046 }
2047 }
2048 } return images;
2049}
2050
2051MSHook(void, BKSDisplayServicesSetSystemAppExitedImagePath, NSString *path) {
2052 if (NSString *themed = $getTheme$($useScale$([NSArray arrayWithObject:@"SystemAppExited.png"])))
2053 path = themed;
2054 _BKSDisplayServicesSetSystemAppExitedImagePath(path);
2055}
2056
2057#define WBRename(name, sel, imp) \
2058 MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp, &_ ## name ## $ ## imp)
2059
2060template <typename Type_>
2061static void msset(Type_ &function, MSImageRef image, const char *name) {
2062 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
2063}
2064
2065#define WBHookSymbol(image, function) \
2066 msset(function, image, "_" #function)
2067
2068template <typename Type_>
2069static void dlset(Type_ &function, const char *name) {
2070 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
2071}
2072
2073// %hook CGImageReadCreateWithFile() {{{
2074MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
2075 if (Debug_)
2076 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
2077 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2078 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
2079 [pool release];
2080 return value;
2081}
2082
2083MSHook(void *, CGImageSourceCreateWithFile, NSString *path, NSDictionary *options) {
2084 if (Debug_)
2085 NSLog(@"WB:Debug: CGImageSourceCreateWithFile(%@, %@)", path, options);
2086 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2087 void *value(_CGImageSourceCreateWithFile([path wb$themedPath], options));
2088 [pool release];
2089 return value;
2090}
2091
2092MSHook(void *, CGImageSourceCreateWithURL, NSURL *url, NSDictionary *options) {
2093 if (Debug_)
2094 NSLog(@"WB:Debug: CGImageSourceCreateWithURL(%@, %@)", url, options);
2095 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2096 if ([url isFileURL])
2097 url = [NSURL fileURLWithPath:[[url path] wb$themedPath]];
2098 void *value(_CGImageSourceCreateWithURL(url, options));
2099 [pool release];
2100 return value;
2101}
2102// }}}
2103
2104static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
2105 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
2106 if (style == nil || [style length] == 0)
2107 style = @"font-family: Helvetica; font-size: 12px";
2108 //NSLog(@"XXX:drawP(%@ | %@)", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
2109 [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
2110}
2111
2112static void NSString$drawInRect$withStyle$(NSString *self, SEL _cmd, CGRect rect, NSString *style) {
2113 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
2114 if (style == nil || [style length] == 0)
2115 style = @"font-family: Helvetica; font-size: 12px";
2116 //NSLog(@"XXX:drawR(%@ | %@)", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
2117 return [[WBMarkup sharedMarkup] drawString:self inRect:rect withStyle:style];
2118}
2119
2120static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, CGFloat width) {
2121 if (style == nil || [style length] == 0)
2122 style = @"font-family: Helvetica; font-size: 12px";
2123 CGSize size([[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width]);
2124 //NSLog(@"XXX:size(%@ | %@) = [%g %g]", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "], size.width, size.height);
2125 return size;
2126}
2127
2128static void SBInitialize() {
2129 if (SummerBoard_) {
2130 WBRename(SBApplication, pathForIcon, pathForIcon);
2131 WBRename(SBApplicationIcon, icon, icon);
2132 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
2133 }
2134
2135 WBRename(SBBookmarkIcon, icon, icon);
2136 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
2137 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
2138 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
2139 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
2140
2141 WBRename(SBWidgetApplicationIcon, icon, icon);
2142
2143 WBRename(SBDockIconListView, setFrame:, setFrame$);
2144 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
2145
2146 if (kCFCoreFoundationVersionNumber < 600 || SummerBoard_)
2147 WBRename(SBIconLabel, drawRect:, drawRect$);
2148 else if (kCFCoreFoundationVersionNumber < 700) {
2149 WBRename(SBIconLabel, buildLabelImage, buildLabelImage);
2150 } else {
2151 WBRename(SBIconLabelImageParameters, hash, hash);
2152 WBRename($SBIconView, _labelImageParametersForIcon:location:, _labelImageParametersForIcon$location$);
2153 WBRename(SBIconView, _labelImageParameters, _labelImageParameters);
2154 WBRename($SBIconLabelImage, _drawLabelImageForParameters:, _drawLabelImageForParameters$);
2155 }
2156
2157 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
2158 WBRename(SBIconLabel, setInDock:, setInDock$);
2159
2160 WBRename(SBIconList, didMoveToSuperview, didMoveToSuperview);
2161 WBRename(SBIconList, setFrame:, setFrame$);
2162
2163 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
2164 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
2165 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
2166 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
2167
2168 if (kCFCoreFoundationVersionNumber < 800) {
2169 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
2170 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
2171 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
2172 }
2173
2174 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
2175
2176 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
2177 if (kCFCoreFoundationVersionNumber >= 700)
2178 WBRename(SBAwayView, _addSubview:positioned:relativeTo:, _addSubview$positioned$relativeTo$);
2179
2180 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
2181 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
2182 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
2183 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
2184 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
2185 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
2186 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
2187 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
2188
2189 if (SummerBoard_)
2190 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
2191}
2192
2193/*MSHook(int, open, const char *path, int oflag, mode_t mode) {
2194 int fd(_open(path, oflag, mode));
2195
2196 static bool no(false);
2197 if (no) return fd;
2198 no = true;
2199
2200 if (strstr(path, "/icon") != NULL)
2201 MSHookProcess(-1, "");
2202
2203 if (fd == -1 && errno == EFAULT)
2204 NSLog(@"open(%p, %#x, %#o) = %d\n", path, oflag, mode, fd);
2205 else
2206 NSLog(@"open(\"%s\", %#x, %#o) = %d\n", path, oflag, mode, fd);
2207
2208 no = false;
2209 return fd;
2210}*/
2211
2212MSInitialize {
2213 $objc_setAssociatedObject = reinterpret_cast<void (*)(id, void *, id value, objc_AssociationPolicy)>(dlsym(RTLD_DEFAULT, "objc_setAssociatedObject"));
2214 $objc_getAssociatedObject = reinterpret_cast<id (*)(id, void *)>(dlsym(RTLD_DEFAULT, "objc_getAssociatedObject"));
2215 $objc_removeAssociatedObjects = reinterpret_cast<void (*)(id)>(dlsym(RTLD_DEFAULT, "objc_removeAssociatedObjects"));
2216
2217 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2218
2219 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
2220 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
2221
2222 Manager_ = [[NSFileManager defaultManager] retain];
2223 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
2224
2225 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
2226
2227 // Load Settings.plist {{{
2228 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
2229 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
2230 SummerBoard_ = [value boolValue];
2231 else
2232 SummerBoard_ = true;
2233
2234 if (NSNumber *value = [settings objectForKey:@"Debug"])
2235 Debug_ = [value boolValue];
2236 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
2237 UIDebug_ = [value boolValue];
2238
2239 NSArray *themes([settings objectForKey:@"Themes"]);
2240 if (themes == nil)
2241 if (NSString *theme = [settings objectForKey:@"Theme"])
2242 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
2243 theme, @"Name",
2244 [NSNumber numberWithBool:true], @"Active",
2245 nil]];
2246
2247 if (themes != nil)
2248 for (NSDictionary *theme in themes) {
2249 NSNumber *active([theme objectForKey:@"Active"]);
2250 if (![active boolValue])
2251 continue;
2252
2253 NSString *name([theme objectForKey:@"Name"]);
2254 if (name == nil)
2255 continue;
2256
2257 #define testForTheme(format...) \
2258 { \
2259 NSString *path = [NSString stringWithFormat:format]; \
2260 if ([Manager_ fileExistsAtPath:path]) { \
2261 [Themes_ addObject:path]; \
2262 continue; \
2263 } \
2264 }
2265
2266 testForTheme(@"/Library/Themes/%@.theme", name)
2267 testForTheme(@"/Library/Themes/%@", name)
2268 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
2269
2270 }
2271 }
2272 // }}}
2273 // Merge Info.plist {{{
2274 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2275
2276 for (NSString *theme in Themes_)
2277 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
2278 for (NSString *key in [info allKeys])
2279 if ([Info_ objectForKey:key] == nil)
2280 [Info_ setObject:[info objectForKey:key] forKey:key];
2281 // }}}
2282
2283 // AppSupport {{{
2284 if (MSImageRef image = MSGetImageByName("/System/Library/PrivateFrameworks/AppSupport.framework/AppSupport")) {
2285 NSArray *(*CPBitmapCreateImagesFromPath)(NSString *, NSDictionary **, void *, void *);
2286 msset(CPBitmapCreateImagesFromPath, image, "_CPBitmapCreateImagesFromPath");
2287 MSHookFunction(CPBitmapCreateImagesFromPath, MSHake(CPBitmapCreateImagesFromPath));
2288 }
2289 // }}}
2290 // AudioToolbox {{{
2291 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
2292 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long, char *, bool &);
2293 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
2294 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
2295
2296 bool (*_Z24GetFileNameForThisActionmPcmRb)(unsigned long, char *, unsigned long, bool &);
2297 msset(_Z24GetFileNameForThisActionmPcmRb, image, "__Z24GetFileNameForThisActionmPcmRb");
2298 MSHookFunction(_Z24GetFileNameForThisActionmPcmRb, &$_Z24GetFileNameForThisActionmPcmRb, &__Z24GetFileNameForThisActionmPcmRb);
2299 }
2300 // }}}
2301 // BackBoardServices {{{
2302 if (MSImageRef image = MSGetImageByName("/System/Library/PrivateFrameworks/BackBoardServices.framework/BackBoardServices")) {
2303 void (*BKSDisplayServicesSetSystemAppExitedImagePath)(NSString *path);
2304 msset(BKSDisplayServicesSetSystemAppExitedImagePath, image, "_BKSDisplayServicesSetSystemAppExitedImagePath");
2305 MSHookFunction(BKSDisplayServicesSetSystemAppExitedImagePath, MSHake(BKSDisplayServicesSetSystemAppExitedImagePath));
2306 }
2307 // }}}
2308 // GraphicsServices {{{
2309 if (true) {
2310 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
2311 }
2312 // }}}
2313 // ImageIO {{{
2314 MSImageRef imageio = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO");
2315 if (imageio == NULL)
2316 imageio = MSGetImageByName("/System/Library/PrivateFrameworks/ImageIO.framework/ImageIO");
2317 if (MSImageRef image = imageio) {
2318 void *(*CGImageReadCreateWithFile)(NSString *, int) = NULL;
2319 if (kCFCoreFoundationVersionNumber > 700) // XXX: iOS 6.x
2320 CGImageReadCreateWithFile = NULL;
2321 else {
2322 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
2323 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
2324 }
2325
2326 if (CGImageReadCreateWithFile == NULL) {
2327 void *(*CGImageSourceCreateWithFile)(NSString *, NSDictionary *);
2328 msset(CGImageSourceCreateWithFile, image, "_CGImageSourceCreateWithFile");
2329 MSHookFunction(CGImageSourceCreateWithFile, MSHake(CGImageSourceCreateWithFile));
2330
2331 void *(*CGImageSourceCreateWithURL)(NSURL *, NSDictionary *);
2332 msset(CGImageSourceCreateWithURL, image, "_CGImageSourceCreateWithURL");
2333 MSHookFunction(CGImageSourceCreateWithURL, MSHake(CGImageSourceCreateWithURL));
2334 }
2335 }
2336 // }}}
2337 // SpringBoard {{{
2338 if (SpringBoard_) {
2339 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
2340 Papered_ = $getTheme$(Wallpapers_) != nil;
2341 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
2342
2343 CFNotificationCenterAddObserver(
2344 CFNotificationCenterGetDarwinNotifyCenter(),
2345 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, CFNotificationSuspensionBehaviorCoalesce
2346 );
2347
2348 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
2349 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
2350 if (MediaPlayer != nil)
2351 [MediaPlayer load];
2352
2353 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
2354 $MPVideoView = objc_getClass("MPVideoView");
2355 }
2356
2357 SBInitialize();
2358 }
2359 // }}}
2360 // UIKit {{{
2361 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/UIKit.framework/UIKit")) {
2362#ifdef __LP64__
2363 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v40@0:8{CGPoint=dd}16@32");
2364 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v56@0:8{CGRect={CGSize=dd}{CGSize=dd}}16@48");
2365 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=dd}32@0:8@16d24");
2366#else
2367 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
2368 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v28@0:4{CGRect={CGSize=ff}{CGSize=ff}}8@24");
2369 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
2370#endif
2371
2372 WBHookSymbol(image, _UIKitBundle);
2373 WBHookSymbol(image, _UIPackedImageTableGetIdentifierForName);
2374 WBHookSymbol(image, _UISharedImageNameGetIdentifier);
2375
2376 MSHookFunction(_UIImageWithName, MSHake(_UIImageWithName));
2377
2378 WBHookSymbol(image, _UIApplicationImageWithName);
2379 MSHookFunction(_UIApplicationImageWithName, MSHake(_UIApplicationImageWithName));
2380
2381 WBHookSymbol(image, _UIImageWithNameInDomain);
2382 MSHookFunction(_UIImageWithNameInDomain, MSHake(_UIImageWithNameInDomain));
2383
2384 WBHookSymbol(image, _UIImageWithNameUsingCurrentIdiom);
2385 MSHookFunction(_UIImageWithNameUsingCurrentIdiom, MSHake(_UIImageWithNameUsingCurrentIdiom));
2386
2387 WBHookSymbol(image, _UIImageWithDeviceSpecificName);
2388 MSHookFunction(_UIImageWithDeviceSpecificName, MSHake(_UIImageWithDeviceSpecificName));
2389
2390 SEL includeEmoji(@selector(_legacy_drawAtPoint:forWidth:withFont:lineBreakMode:letterSpacing:includeEmoji:));
2391 if (![@"" respondsToSelector:includeEmoji])
2392 includeEmoji = @selector(drawAtPoint:forWidth:withFont:lineBreakMode:letterSpacing:includeEmoji:);
2393 MSHookMessage($NSString, includeEmoji, MSHake(NSString$drawAtPoint$forWidth$withFont$lineBreakMode$letterSpacing$includeEmoji$));
2394
2395 SEL letterSpacing(@selector(_legacy_sizeWithFont:forWidth:lineBreakMode:letterSpacing:));
2396 if (![@"" respondsToSelector:letterSpacing])
2397 letterSpacing = @selector(sizeWithFont:forWidth:lineBreakMode:letterSpacing:);
2398 MSHookMessage($NSString, letterSpacing, MSHake(NSString$sizeWithFont$forWidth$lineBreakMode$letterSpacing$));
2399
2400 SEL sizeWithFont(@selector(_legacy_sizeWithFont:));
2401 if (![@"" respondsToSelector:sizeWithFont])
2402 sizeWithFont = @selector(sizeWithFont:);
2403 MSHookMessage($NSString, sizeWithFont, MSHake(NSString$sizeWithFont$));
2404 }
2405 // }}}
2406
2407 //MSHookFunction(reinterpret_cast<int (*)(const char *, int, mode_t)>(&open), MSHake(open));
2408
2409 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
2410 NSError *error(nil);
2411 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
2412 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
2413 nil] error:&error])
2414 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);
2415 }
2416
2417 [pool release];
2418}