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