]> git.saurik.com Git - winterboard.git/blob - Library.mm
7d44ff25f5395651605b840648ceef0a1a21498c
[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 }
1319
1320 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1321 extern "C" CGColorRef CGGStateGetFillColor(void *);
1322 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1323 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1324
1325 /* WBTimeLabel {{{ */
1326 @interface WBTimeLabel : NSProxy {
1327 NSString *time_;
1328 _transient SBStatusBarTimeView *view_;
1329 }
1330
1331 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1332
1333 @end
1334
1335 @implementation WBTimeLabel
1336
1337 - (void) dealloc {
1338 [time_ release];
1339 [super dealloc];
1340 }
1341
1342 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1343 time_ = [time retain];
1344 view_ = view;
1345 return self;
1346 }
1347
1348 - (NSString *) description {
1349 return time_;
1350 }
1351
1352 WBDelegate(time_)
1353
1354 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1355 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1356 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1357
1358 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1359 "font-family: Helvetica; "
1360 "font-weight: bold; "
1361 "font-size: 14px; "
1362 "color: %@; "
1363 "%@", _mode ? @"white" : @"black", custom]];
1364
1365 return CGSizeZero;
1366 }
1367
1368 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1369 }
1370
1371 @end
1372 /* }}} */
1373 /* WBBadgeLabel {{{ */
1374 @interface WBBadgeLabel : NSProxy {
1375 NSString *badge_;
1376 }
1377
1378 - (id) initWithBadge:(NSString *)badge;
1379 - (NSString *) description;
1380
1381 @end
1382
1383 @implementation WBBadgeLabel
1384
1385 - (void) dealloc {
1386 [badge_ release];
1387 [super dealloc];
1388 }
1389
1390 - (id) initWithBadge:(NSString *)badge {
1391 badge_ = [badge retain];
1392 return self;
1393 }
1394
1395 - (NSString *) description {
1396 return [badge_ description];
1397 }
1398
1399 WBDelegate(badge_)
1400
1401 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1402 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1403 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1404 "font-family: Helvetica; "
1405 "font-weight: bold; "
1406 "font-size: 17px; "
1407 "color: white; "
1408 "%@", custom]];
1409
1410 return CGSizeZero;
1411 }
1412
1413 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1414 }
1415
1416 @end
1417 /* }}} */
1418
1419 // IconAlpha {{{
1420 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1421 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1422 alpha = [number floatValue];
1423 return MSOldCall(alpha);
1424 }
1425
1426 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1427 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1428 alpha = [number floatValue];
1429 return MSOldCall(alpha);
1430 }
1431
1432 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1433 if ((self = MSOldCall()) != nil) {
1434 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1435 // XXX: note: this is overridden above, which is silly
1436 float alpha([number floatValue]);
1437 if ([self respondsToSelector:@selector(setIconImageAlpha:)])
1438 [self setIconImageAlpha:alpha];
1439 if ([self respondsToSelector:@selector(setIconLabelAlpha:)])
1440 [self setIconLabelAlpha:alpha];
1441 if ([self respondsToSelector:@selector(setAlpha:)])
1442 [self setAlpha:alpha];
1443 }
1444 } return self;
1445 }
1446
1447 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1448 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1449 alpha = [number floatValue];
1450 return MSOldCall(alpha);
1451 }
1452 // }}}
1453
1454 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1455 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1456 id &_badge(MSHookIvar<id>(self, "_badge"));
1457 if (_badge != nil)
1458 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1459 _badge = label;
1460 } return self;
1461 }
1462
1463 void SBStatusBarController$setStatusBarMode(int &mode) {
1464 if (Debug_)
1465 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1466 if (mode < 100) // 104:hidden 105:glowing
1467 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1468 mode = [number intValue];
1469 }
1470
1471 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1472 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1473 SBStatusBarController$setStatusBarMode(mode);
1474 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1475 }*/
1476
1477 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1478 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1479 SBStatusBarController$setStatusBarMode(mode);
1480 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1481 }
1482
1483 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) {
1484 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1485 SBStatusBarController$setStatusBarMode(mode);
1486 //NSLog(@"mode=%u", mode);
1487 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1488 }
1489
1490 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1491 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1492 mode = [number intValue];
1493 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1494 }*/
1495
1496 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1497 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1498 if (Debug_)
1499 NSLog(@"operatorNameStyle= %@", style);
1500 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1501 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1502 return style;
1503 }
1504
1505 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1506 if (Debug_)
1507 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1508 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1509 }
1510
1511 // XXX: replace this with [SBStatusBarTimeView tile]
1512 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1513 id &_time(MSHookIvar<id>(self, "_time"));
1514 if (_time != nil && [_time class] != [WBTimeLabel class])
1515 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1516 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1517 }
1518
1519 @interface UIView (WinterBoard)
1520 - (bool) wb$isWBImageView;
1521 - (void) wb$logHierarchy;
1522 - (void) wb$setBackgroundColor:(UIColor *)color;
1523 @end
1524
1525 @implementation UIView (WinterBoard)
1526
1527 - (bool) wb$isWBImageView {
1528 return false;
1529 }
1530
1531 - (void) wb$logHierarchy {
1532 WBLogHierarchy(self);
1533 }
1534
1535 - (void) wb$setBackgroundColor:(UIColor *)color {
1536 [self setBackgroundColor:color];
1537 for (UIView *child in [self subviews])
1538 [child wb$setBackgroundColor:color];
1539 }
1540
1541 @end
1542
1543 @interface WBImageView : UIImageView {
1544 }
1545
1546 - (bool) wb$isWBImageView;
1547 - (void) wb$updateFrame;
1548 @end
1549
1550 @implementation WBImageView
1551
1552 - (bool) wb$isWBImageView {
1553 return true;
1554 }
1555
1556 - (void) wb$updateFrame {
1557 CGRect frame([self frame]);
1558 frame.origin.y = 0;
1559
1560 for (UIView *view(self); ; ) {
1561 view = [view superview];
1562 if (view == nil)
1563 break;
1564 frame.origin.y -= [view frame].origin.y;
1565 }
1566
1567 [self setFrame:frame];
1568 }
1569
1570 @end
1571
1572 static void SBIconList$updateFrames$(SBIconList *self) {
1573 NSArray *subviews([self subviews]);
1574 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1575 if (view != nil && [view wb$isWBImageView])
1576 [view wb$updateFrame];
1577 }
1578
1579 MSHook(void, SBIconList$didMoveToSuperview, SBIconList *self, SEL sel) {
1580 SBIconList$updateFrames$(self);
1581 _SBIconList$didMoveToSuperview(self, sel);
1582 }
1583
1584 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1585 SBIconList$updateFrames$(self);
1586 _SBIconList$setFrame$(self, sel, frame);
1587 }
1588
1589 static void $addPerPageView$(unsigned i, UIView *list) {
1590 NSString *path($getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]]));
1591 if (path == nil)
1592 return;
1593
1594 NSArray *subviews([list subviews]);
1595
1596 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1597 if (view == nil || ![view wb$isWBImageView]) {
1598 view = [[[WBImageView alloc] init] autorelease];
1599 [list insertSubview:view atIndex:0];
1600 }
1601
1602 UIImage *image([UIImage imageWithContentsOfFile:path]);
1603
1604 CGRect frame([view frame]);
1605 frame.size = [image size];
1606 [view setFrame:frame];
1607
1608 [view setImage:image];
1609 [view wb$updateFrame];
1610 }
1611
1612 static void $addPerPageViews$(NSArray *lists) {
1613 for (unsigned i(0), e([lists count]); i != e; ++i)
1614 $addPerPageView$(i, [lists objectAtIndex:i]);
1615 }
1616
1617 MSInstanceMessageHook0(void, SBIconController, updateNumberOfRootIconLists) {
1618 NSArray *&_rootIconLists(MSHookIvar<NSArray *>(self, "_rootIconLists"));
1619 $addPerPageViews$(_rootIconLists);
1620 return MSOldCall();
1621 }
1622
1623 MSInstanceMessageHook0(void, SBIconContentView, layoutSubviews) {
1624 MSOldCall();
1625
1626 if (SBIconController *controller = [$SBIconController sharedInstance]) {
1627 UIView *&_dockContainerView(MSHookIvar<UIView *>(controller, "_dockContainerView"));
1628 if (&_dockContainerView != NULL)
1629 [[_dockContainerView superview] bringSubviewToFront:_dockContainerView];
1630 }
1631 }
1632
1633 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1634 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1635 $addPerPageViews$([_iconModel iconLists]);
1636 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1637 }
1638
1639 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1640 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1641 if (self != nil)
1642 [self setClipsToBounds:NO];
1643 return self;
1644 }
1645
1646 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1647 static bool gssc(false);
1648 if (!gssc) {
1649 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1650 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1651 gssc = true;
1652
1653 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1654 [Info_ setObject:[NSNumber numberWithBool:(
1655 !Papered_ ||
1656 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1657 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1658 )] forKey:@"UndockedIconLabels"];
1659 }
1660
1661 id &_label(MSHookIvar<id>(self, "_label"));
1662 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1663 docked = true;
1664
1665 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1666 [_label setInDock:docked];
1667
1668 _SBIconLabel$setInDock$(self, sel, docked);
1669 [self setNeedsDisplay];
1670 }
1671
1672 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1673 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1674 }
1675
1676 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1677 _SBDockIconListView$setFrame$(self, sel, frame);
1678 }
1679
1680 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1681 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1682 NSString *identifier = [self bundleIdentifier];
1683 NSLocale *locale = [NSLocale currentLocale];
1684 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1685 if (Debug_)
1686 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1687 NSString *file = table == nil ? @"Localizable" : table;
1688 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1689 NSDictionary *strings;
1690 if ((strings = [Strings_ objectForKey:name]) != nil) {
1691 if (static_cast<id>(strings) != [NSNull null]) strings:
1692 if (NSString *value = [strings objectForKey:key])
1693 return value;
1694 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1695 language, file
1696 ], self, false, false)) {
1697 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1698 [Strings_ setObject:[strings autorelease] forKey:name];
1699 goto strings;
1700 } else goto null;
1701 } else null:
1702 [Strings_ setObject:[NSNull null] forKey:name];
1703 return MSOldCall(key, value, table);
1704 }
1705 // }}}
1706 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1707 MSClassHook(WebCoreFrameBridge)
1708
1709 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1710 if (node == nil)
1711 return CGSizeZero;
1712 void **core(reinterpret_cast<void **>([node _node]));
1713 if (core == NULL || core[6] == NULL)
1714 return CGSizeZero;
1715 return MSOldCall(node, width);
1716 }
1717 // }}}
1718
1719 MSInstanceMessage1(void, SBIconLabel, drawRect, CGRect, rect) {
1720 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1721
1722 int docked;
1723 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1724 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1725
1726 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1727
1728 NSString *style = [NSString stringWithFormat:@""
1729 "font-family: Helvetica; "
1730 "font-weight: bold; "
1731 "color: %@; %@"
1732 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1733 ? @"font-size: 12px; "
1734 : @"font-size: 11px; "
1735 )];
1736
1737 if (IsWild_)
1738 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1739 else if (docked)
1740 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1741
1742 NSString *custom([Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")]);
1743
1744 $drawLabel$(label, [self bounds], style, custom);
1745 }
1746
1747 MSInstanceMessage0(CGImageRef, SBIconLabel, buildLabelImage) {
1748 bool docked((MSHookIvar<unsigned>(self, "_inDock") & 0x2) != 0);
1749
1750 WBStringDrawingState labelState = {NULL, 0, @""
1751 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1752
1753 stringDrawingState_ = &labelState;
1754
1755 //NSLog(@"XXX: +");
1756 CGImageRef image(MSOldCall());
1757 //NSLog(@"XXX: -");
1758
1759 stringDrawingState_ = NULL;
1760 return image;
1761 }
1762
1763 static bool wb$inDock(id parameters) {
1764 return [$objc_getAssociatedObject(parameters, @selector(wb$inDock)) boolValue];
1765 }
1766
1767 MSInstanceMessage0(NSUInteger, SBIconLabelImageParameters, hash) {
1768 return MSOldCall() + (wb$inDock(self) ? 0xdeadbeef : 0xd15ea5e);
1769 }
1770
1771 MSClassMessage2(id, SBIconView, _labelImageParametersForIcon,location, id, icon, int, location) {
1772 if (id parameters = MSOldCall(icon, location)) {
1773 $objc_setAssociatedObject(parameters, @selector(wb$inDock), [NSNumber numberWithBool:(location == 1)], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1774 return parameters;
1775 } return nil;
1776 }
1777
1778 MSClassMessage1(UIImage *, SBIconLabelImage, _drawLabelImageForParameters, id, parameters) {
1779 bool docked(wb$inDock(parameters));
1780
1781 WBStringDrawingState labelState = {NULL, 0, @""
1782 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1783
1784 stringDrawingState_ = &labelState;
1785
1786 //NSLog(@"XXX: +");
1787 UIImage *image(MSOldCall(parameters));
1788 //NSLog(@"XXX: -");
1789
1790 stringDrawingState_ = NULL;
1791 return image;
1792 }
1793
1794 // ChatKit {{{
1795 MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1796 if ((self = MSOldCall(frame, delegate)) != nil) {
1797 [self setBackgroundColor:[UIColor clearColor]];
1798 } return self;
1799 }
1800
1801 MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1802 return SMSBackgrounded_ ? NO : MSOldCall();
1803 }
1804
1805 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1806 [self wb$setBackgroundColor:[UIColor clearColor]];
1807 return MSOldCall();
1808 }
1809
1810 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1811 MSOldCall(balloon);
1812 [balloon setBackgroundColor:[UIColor clearColor]];
1813 }
1814
1815 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1816 MSOldCall([UIColor clearColor]);
1817 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1818 }
1819
1820 // iOS >= 5.0
1821 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1822 if ((self = MSOldCall(style, reuse)) != nil) {
1823 [self setBackgroundColor:[UIColor clearColor]];
1824 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1825 } return self;
1826 }
1827
1828 // iOS << 5.0
1829 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1830 if ((self = MSOldCall(style, reuse)) != nil) {
1831 [self setBackgroundColor:[UIColor clearColor]];
1832 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1833 } return self;
1834 }
1835
1836 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1837 if ((self = MSOldCall(style, reuse)) != nil) {
1838 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1839 [_label setBackgroundColor:[UIColor clearColor]];
1840 } return self;
1841 }
1842
1843 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1844 MSOldCall(UITableViewCellSeparatorStyleNone);
1845 }
1846
1847 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1848 if ((self = MSOldCall(frame, style)) != nil) {
1849 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1850 } return self;
1851 }
1852
1853 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1854 MSOldCall();
1855
1856 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1857 if (UIImage *image = $getImage$(path)) {
1858 SMSBackgrounded_ = true;
1859
1860 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1861 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1862 UIView *table;
1863 if (&_transcriptTable != NULL)
1864 table = _transcriptTable;
1865 else if (&_transcriptLayer != NULL)
1866 table = _transcriptLayer;
1867 else
1868 table = nil;
1869
1870 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1871 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1872
1873 if (table == nil)
1874 [placard insertSubview:background atIndex:0];
1875 else {
1876 [table setBackgroundColor:[UIColor clearColor]];
1877 [placard insertSubview:background belowSubview:table];
1878 }
1879 }
1880 }
1881 // }}}
1882
1883 MSInstanceMessage2(UISharedArtwork *, UISharedArtwork, initWithName,inBundle, NSString *, name, NSBundle *, bundle) {
1884 if ((self = MSOldCall(name, bundle)) != nil) {
1885 $objc_setAssociatedObject(self, @selector(wb$bundle), bundle, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1886 } return self;
1887 }
1888
1889 MSInstanceMessage1(UIImage *, UIImageTableArtwork, imageNamed, NSString *, name) {
1890 NSBundle *bundle($objc_getAssociatedObject(self, @selector(wb$bundle)));
1891 if (Debug_)
1892 NSLog(@"WB:Debug:[UIImageTableArtwork[%@] imageNamed:\"%@\"]", bundle, name);
1893 if (bundle == nil)
1894 return MSOldCall(name);
1895 UIImage *image = [UIImages_ objectForKey:name];
1896 if (image != nil)
1897 return reinterpret_cast<id>(image) == [NSNull null] ? MSOldCall(name) : image;
1898 if (NSString *path = $pathForFile$inBundle$(name, bundle, true, true))
1899 image = $getImage$(path);
1900 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:name];
1901 if (image != nil)
1902 return image;
1903
1904 image = MSOldCall(name);
1905
1906 if (UIDebug_) {
1907 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1908 if (![Manager_ fileExistsAtPath:path])
1909 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1910 }
1911
1912 return image;
1913 }
1914
1915 // %hook _UIImageWithName() {{{
1916 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1917 if (Debug_)
1918 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1919 if (name == nil)
1920 return nil;
1921
1922 int identifier;
1923 bool packed;
1924
1925 if (_UIPackedImageTableGetIdentifierForName != NULL)
1926 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1927 else if (_UISharedImageNameGetIdentifier != NULL) {
1928 identifier = _UISharedImageNameGetIdentifier(name);
1929 packed = identifier != -1;
1930 } else {
1931 identifier = -1;
1932 packed = false;
1933 }
1934
1935 if (Debug_)
1936 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1937
1938 if (!packed)
1939 return __UIImageWithName(name);
1940 else {
1941 NSNumber *key([NSNumber numberWithInt:identifier]);
1942 UIImage *image([UIImages_ objectForKey:key]);
1943 if (image != nil)
1944 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1945 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true, true))
1946 image = $getImage$(path);
1947 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1948 if (image != nil)
1949 return image;
1950
1951 image = __UIImageWithName(name);
1952
1953 if (UIDebug_) {
1954 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1955 if (![Manager_ fileExistsAtPath:path])
1956 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1957 }
1958
1959 return image;
1960 }
1961 }
1962 // }}}
1963 // %hook _UIImageWithNameInDomain() {{{
1964 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1965 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1966 UIImage *image([PathImages_ objectForKey:key]);
1967 if (image != nil)
1968 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1969 if (Debug_)
1970 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1971 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1972 image = $getImage$(path);
1973 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1974 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1975 }
1976 // }}}
1977
1978 // %hook GSFontCreateWithName() {{{
1979 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1980 if (Debug_)
1981 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1982 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1983 name = [font UTF8String];
1984 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1985 // size *= [scale floatValue];
1986 return _GSFontCreateWithName(name, traits, size);
1987 }
1988 // }}}
1989
1990 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1991 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1992
1993 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1994
1995 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1996 if (Debug_)
1997 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1998 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1999 if (Debug_)
2000 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
2001
2002 if (value) {
2003 NSString *path = [NSString stringWithUTF8String:a1];
2004 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
2005 NSString *file = [path substringFromIndex:31];
2006 for (NSString *theme in Themes_) {
2007 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
2008 if ([Manager_ fileExistsAtPath:path]) {
2009 strcpy(a1, [path UTF8String]);
2010 break;
2011 }
2012 }
2013 }
2014 }
2015 return value;
2016 }
2017
2018 static void ChangeWallpaper(
2019 CFNotificationCenterRef center,
2020 void *observer,
2021 CFStringRef name,
2022 const void *object,
2023 CFDictionaryRef info
2024 ) {
2025 if (Debug_)
2026 NSLog(@"WB:Debug:ChangeWallpaper!");
2027
2028 UIImage *image;
2029 if (WallpaperFile_ != nil) {
2030 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
2031 if (image != nil)
2032 image = [image autorelease];
2033 } else image = nil;
2034
2035 if (WallpaperImage_ != nil)
2036 [WallpaperImage_ setImage:image];
2037 if (WallpaperPage_ != nil)
2038 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
2039
2040 }
2041
2042 MSHook(NSArray *, CPBitmapCreateImagesFromPath, NSString *path, NSDictionary **names, void *arg2, void *arg3) {
2043 NSArray *images(_CPBitmapCreateImagesFromPath(path, names, arg2, arg3));
2044 if (images != NULL && *names != nil && CFGetTypeID((CFTypeRef) *names) == CFDictionaryGetTypeID()) {
2045 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:path]) {
2046 NSMutableArray *copy([images mutableCopy]);
2047 [images release];
2048 images = copy;
2049
2050 NSString *file([path stringByResolvingSymlinksInPath]);
2051 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
2052 if ([file hasPrefix:prefix]) {
2053 NSUInteger length([prefix length]);
2054 if (length != [file length]) {
2055 NSEnumerator *enumerator([*names keyEnumerator]);
2056 while (NSString *name = [enumerator nextObject]) {
2057 NSString *png([name stringByAppendingString:@".png"]);
2058 if (NSString *themed = $pathForFile$inBundle$(png, bundle, false, true)) {
2059 NSUInteger index([[*names objectForKey:name] intValue]);
2060 UIImage *image($getImage$(themed));
2061 CGImageRef cg([image CGImage]);
2062 [copy replaceObjectAtIndex:index withObject:(id)cg];
2063 }
2064 }
2065 }
2066 }
2067 }
2068 } return images;
2069 }
2070
2071 #define WBRename(name, sel, imp) \
2072 MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp, &_ ## name ## $ ## imp)
2073
2074 template <typename Type_>
2075 static void msset(Type_ &function, MSImageRef image, const char *name) {
2076 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
2077 }
2078
2079 template <typename Type_>
2080 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
2081 struct nlist &name(nl[index]);
2082 uintptr_t value(name.n_value);
2083 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
2084 value |= 0x00000001;
2085 function = reinterpret_cast<Type_>(value);
2086 }
2087
2088 template <typename Type_>
2089 static void dlset(Type_ &function, const char *name) {
2090 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
2091 }
2092
2093 // %hook CGImageReadCreateWithFile() {{{
2094 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
2095 if (Debug_)
2096 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
2097 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2098 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
2099 [pool release];
2100 return value;
2101 }
2102
2103 MSHook(void *, CGImageSourceCreateWithFile, NSString *path, NSDictionary *options) {
2104 if (Debug_)
2105 NSLog(@"WB:Debug: CGImageSourceCreateWithFile(%@, %@)", path, options);
2106 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2107 void *value(_CGImageSourceCreateWithFile([path wb$themedPath], options));
2108 [pool release];
2109 return value;
2110 }
2111
2112 MSHook(void *, CGImageSourceCreateWithURL, NSURL *url, NSDictionary *options) {
2113 if (Debug_)
2114 NSLog(@"WB:Debug: CGImageSourceCreateWithURL(%@, %@)", url, options);
2115 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2116 if ([url isFileURL])
2117 url = [NSURL fileURLWithPath:[[url path] wb$themedPath]];
2118 void *value(_CGImageSourceCreateWithURL(url, options));
2119 [pool release];
2120 return value;
2121 }
2122 // }}}
2123
2124 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
2125 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
2126 if (style == nil || [style length] == 0)
2127 style = @"font-family: Helvetica; font-size: 12px";
2128 //NSLog(@"XXX:drawP(%@ | %@)", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
2129 [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
2130 }
2131
2132 static void NSString$drawInRect$withStyle$(NSString *self, SEL _cmd, CGRect rect, NSString *style) {
2133 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
2134 if (style == nil || [style length] == 0)
2135 style = @"font-family: Helvetica; font-size: 12px";
2136 //NSLog(@"XXX:drawR(%@ | %@)", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
2137 return [[WBMarkup sharedMarkup] drawString:self inRect:rect withStyle:style];
2138 }
2139
2140 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
2141 if (style == nil || [style length] == 0)
2142 style = @"font-family: Helvetica; font-size: 12px";
2143 CGSize size([[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width]);
2144 //NSLog(@"XXX:size(%@ | %@) = [%g %g]", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "], size.width, size.height);
2145 return size;
2146 }
2147
2148 static void SBInitialize() {
2149 if (SummerBoard_) {
2150 WBRename(SBApplication, pathForIcon, pathForIcon);
2151 WBRename(SBApplicationIcon, icon, icon);
2152 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
2153 }
2154
2155 WBRename(SBBookmarkIcon, icon, icon);
2156 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
2157 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
2158 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
2159 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
2160
2161 WBRename(SBWidgetApplicationIcon, icon, icon);
2162
2163 WBRename(SBDockIconListView, setFrame:, setFrame$);
2164 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
2165
2166 if (kCFCoreFoundationVersionNumber < 600 || SummerBoard_)
2167 WBRename(SBIconLabel, drawRect:, drawRect$);
2168 else if (kCFCoreFoundationVersionNumber < 700) {
2169 WBRename(SBIconLabel, buildLabelImage, buildLabelImage);
2170 } else {
2171 WBRename(SBIconLabelImageParameters, hash, hash);
2172 WBRename($SBIconView, _labelImageParametersForIcon:location:, _labelImageParametersForIcon$location$);
2173 WBRename($SBIconLabelImage, _drawLabelImageForParameters:, _drawLabelImageForParameters$);
2174 }
2175
2176 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
2177 WBRename(SBIconLabel, setInDock:, setInDock$);
2178
2179 WBRename(SBIconList, didMoveToSuperview, didMoveToSuperview);
2180 WBRename(SBIconList, setFrame:, setFrame$);
2181
2182 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
2183 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
2184 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
2185 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
2186
2187 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
2188 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
2189 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
2190
2191 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
2192
2193 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
2194 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
2195 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
2196 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
2197 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
2198 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
2199 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
2200 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
2201 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
2202
2203 if (SummerBoard_)
2204 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
2205 }
2206
2207 /*MSHook(int, open, const char *path, int oflag, mode_t mode) {
2208 int fd(_open(path, oflag, mode));
2209
2210 static bool no(false);
2211 if (no) return fd;
2212 no = true;
2213
2214 if (strstr(path, "/icon") != NULL)
2215 MSHookProcess(-1, "");
2216
2217 if (fd == -1 && errno == EFAULT)
2218 NSLog(@"open(%p, %#x, %#o) = %d\n", path, oflag, mode, fd);
2219 else
2220 NSLog(@"open(\"%s\", %#x, %#o) = %d\n", path, oflag, mode, fd);
2221
2222 no = false;
2223 return fd;
2224 }*/
2225
2226 MSInitialize {
2227 $objc_setAssociatedObject = reinterpret_cast<void (*)(id, void *, id value, objc_AssociationPolicy)>(dlsym(RTLD_DEFAULT, "objc_setAssociatedObject"));
2228 $objc_getAssociatedObject = reinterpret_cast<id (*)(id, void *)>(dlsym(RTLD_DEFAULT, "objc_getAssociatedObject"));
2229 $objc_removeAssociatedObjects = reinterpret_cast<void (*)(id)>(dlsym(RTLD_DEFAULT, "objc_removeAssociatedObjects"));
2230
2231 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2232
2233 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
2234 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
2235
2236 Manager_ = [[NSFileManager defaultManager] retain];
2237 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
2238
2239 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
2240
2241 // Load Settings.plist {{{
2242 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
2243 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
2244 SummerBoard_ = [value boolValue];
2245 else
2246 SummerBoard_ = true;
2247
2248 if (NSNumber *value = [settings objectForKey:@"Debug"])
2249 Debug_ = [value boolValue];
2250 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
2251 UIDebug_ = [value boolValue];
2252
2253 NSArray *themes([settings objectForKey:@"Themes"]);
2254 if (themes == nil)
2255 if (NSString *theme = [settings objectForKey:@"Theme"])
2256 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
2257 theme, @"Name",
2258 [NSNumber numberWithBool:true], @"Active",
2259 nil]];
2260
2261 if (themes != nil)
2262 for (NSDictionary *theme in themes) {
2263 NSNumber *active([theme objectForKey:@"Active"]);
2264 if (![active boolValue])
2265 continue;
2266
2267 NSString *name([theme objectForKey:@"Name"]);
2268 if (name == nil)
2269 continue;
2270
2271 NSString *theme(nil);
2272
2273 #define testForTheme(format...) \
2274 if (theme == nil) { \
2275 NSString *path = [NSString stringWithFormat:format]; \
2276 if ([Manager_ fileExistsAtPath:path]) { \
2277 [Themes_ addObject:path]; \
2278 continue; \
2279 } \
2280 }
2281
2282 testForTheme(@"/Library/Themes/%@.theme", name)
2283 testForTheme(@"/Library/Themes/%@", name)
2284 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
2285
2286 }
2287 }
2288 // }}}
2289 // Merge Info.plist {{{
2290 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2291
2292 for (NSString *theme in Themes_)
2293 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
2294 for (NSString *key in [info allKeys])
2295 if ([Info_ objectForKey:key] == nil)
2296 [Info_ setObject:[info objectForKey:key] forKey:key];
2297 // }}}
2298
2299 // AppSupport {{{
2300 if (MSImageRef image = MSGetImageByName("/System/Library/PrivateFrameworks/AppSupport.framework/AppSupport")) {
2301 NSArray *(*CPBitmapCreateImagesFromPath)(NSString *, NSDictionary **, void *, void *);
2302 msset(CPBitmapCreateImagesFromPath, image, "_CPBitmapCreateImagesFromPath");
2303 MSHookFunction(CPBitmapCreateImagesFromPath, MSHake(CPBitmapCreateImagesFromPath));
2304 }
2305 // }}}
2306 // AudioToolbox {{{
2307 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
2308 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
2309 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
2310 }
2311 // }}}
2312 // GraphicsServices {{{
2313 if (true) {
2314 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
2315 }
2316 // }}}
2317 // ImageIO {{{
2318 MSImageRef imageio = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO");
2319 if (imageio == NULL)
2320 imageio = MSGetImageByName("/System/Library/PrivateFrameworks/ImageIO.framework/ImageIO");
2321 if (MSImageRef image = imageio) {
2322 void *(*CGImageReadCreateWithFile)(NSString *, int);
2323 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
2324 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
2325
2326 if (CGImageReadCreateWithFile == NULL) {
2327 void *(*CGImageSourceCreateWithFile)(NSString *, NSDictionary *);
2328 msset(CGImageSourceCreateWithFile, image, "_CGImageSourceCreateWithFile");
2329 MSHookFunction(CGImageSourceCreateWithFile, MSHake(CGImageSourceCreateWithFile));
2330
2331 void *(*CGImageSourceCreateWithURL)(NSURL *, NSDictionary *);
2332 msset(CGImageSourceCreateWithURL, image, "_CGImageSourceCreateWithURL");
2333 MSHookFunction(CGImageSourceCreateWithURL, MSHake(CGImageSourceCreateWithURL));
2334 }
2335 }
2336 // }}}
2337 // SpringBoard {{{
2338 if (SpringBoard_) {
2339 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
2340 Papered_ = $getTheme$(Wallpapers_) != nil;
2341 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
2342
2343 CFNotificationCenterAddObserver(
2344 CFNotificationCenterGetDarwinNotifyCenter(),
2345 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
2346 );
2347
2348 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
2349 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
2350 if (MediaPlayer != nil)
2351 [MediaPlayer load];
2352
2353 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
2354 $MPVideoView = objc_getClass("MPVideoView");
2355 }
2356
2357 SBInitialize();
2358 }
2359 // }}}
2360 // UIKit {{{
2361 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
2362 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
2363 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v28@0:4{CGRect={CGSize=ff}{CGSize=ff}}8@24");
2364 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
2365
2366 if (kCFCoreFoundationVersionNumber > 700) { // XXX: iOS 6.x
2367 WBRename(UISharedArtwork, initWithName:inBundle:, initWithName$inBundle$);
2368 WBRename(UIImageTableArtwork, imageNamed:, imageNamed$);
2369 } else {
2370 struct nlist nl[6];
2371 memset(nl, 0, sizeof(nl));
2372 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
2373 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
2374 nl[2].n_un.n_name = (char *) "__UIKitBundle";
2375 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
2376 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
2377 nlist(UIKit, nl);
2378
2379 nlset(_UIApplicationImageWithName, nl, 0);
2380 nlset(_UIImageWithNameInDomain, nl, 1);
2381 nlset(_UIKitBundle, nl, 2);
2382 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
2383 nlset(_UISharedImageNameGetIdentifier, nl, 4);
2384
2385 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
2386 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
2387 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
2388 }
2389 }
2390 // }}}
2391
2392 //MSHookFunction(reinterpret_cast<int (*)(const char *, int, mode_t)>(&open), MSHake(open));
2393
2394 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
2395 NSError *error(nil);
2396 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
2397 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
2398 nil] error:&error])
2399 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);
2400 }
2401
2402 [pool release];
2403 }