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