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