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