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