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