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