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