]> git.saurik.com Git - winterboard.git/blob - Library.mm
Modify sizeOfString: with stringDrawingState_.
[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 unsigned count_;
665 NSString *base_;
666 NSString *info_;
667 } *stringDrawingState_;
668
669 MSInstanceMessageHook4(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode, CGPoint, point, float, width, UIFont *, font, int, mode) {
670 WBStringDrawingState *state(stringDrawingState_);
671 if (state == NULL)
672 return MSOldCall(point, width, font, mode);
673
674 if (--state->count_ == 0)
675 stringDrawingState_ = state->next_;
676 if (state->info_ == nil)
677 return MSOldCall(point, width, font, mode);
678
679 NSString *info([Info_ objectForKey:state->info_]);
680 if (info == nil)
681 return MSOldCall(point, width, font, mode);
682
683 NSString *base(state->base_ ?: @"");
684 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]];
685 return CGSizeZero;
686 }
687
688 MSInstanceMessageHook2(CGSize, NSString, drawAtPoint,withFont, CGPoint, point, UIFont *, font) {
689 WBStringDrawingState *state(stringDrawingState_);
690 if (state == NULL)
691 return MSOldCall(point, font);
692
693 if (--state->count_ == 0)
694 stringDrawingState_ = state->next_;
695 if (state->info_ == nil)
696 return MSOldCall(point, font);
697
698 NSString *info([Info_ objectForKey:state->info_]);
699 if (info == nil)
700 return MSOldCall(point, font);
701
702 NSString *base(state->base_ ?: @"");
703 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]];
704 return CGSizeZero;
705 }
706
707 MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) {
708 WBStringDrawingState *state(stringDrawingState_);
709 if (state == NULL)
710 return MSOldCall(font);
711
712 if (--state->count_ == 0)
713 stringDrawingState_ = state->next_;
714 if (state->info_ == nil)
715 return MSOldCall(font);
716
717 NSString *info([Info_ objectForKey:state->info_]);
718 if (info == nil)
719 return MSOldCall(font);
720
721 NSString *base(state->base_ ?: @"");
722 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info] forWidth:65535];
723 }
724
725 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
726 WBStringDrawingState badgeState = {NULL, 1, @""
727 "color: white;"
728 , @"BadgeStyle"};
729
730 stringDrawingState_ = &badgeState;
731
732 UIImage *image(MSOldCall(text));
733
734 stringDrawingState_ = NULL;
735 return image;
736 }
737
738 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
739 WBStringDrawingState dayState = {NULL, 2, @""
740 "color: white;"
741 // XXX: this is only correct on an iPod dock
742 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
743 , @"CalendarIconDayStyle"};
744
745 WBStringDrawingState sizeState = {&dayState, 7, nil, nil};
746
747 WBStringDrawingState dateState = {&sizeState, 2, @""
748 "color: #333333;"
749 , @"CalendarIconDateStyle"};
750
751 stringDrawingState_ = &dateState;
752
753 UIImage *image(MSOldCall(type));
754
755 stringDrawingState_ = NULL;
756 return image;
757 }
758
759 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
760 NSBundle *bundle([NSBundle mainBundle]);
761
762 CFLocaleRef locale(CFLocaleCopyCurrent());
763 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
764 CFRelease(locale);
765
766 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
767
768 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
769 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
770 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
771 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
772
773 CFRelease(now);
774
775 CFRelease(formatter);
776
777 NSString *datestyle([@""
778 "font-family: Helvetica; "
779 "font-weight: bold; "
780 "color: #333333; "
781 "alpha: 1.0; "
782 "" stringByAppendingString:(IsWild_
783 ? @"font-size: 54px; "
784 : @"font-size: 39px; "
785 )]);
786
787 NSString *daystyle([@""
788 "font-family: Helvetica; "
789 "font-weight: bold; "
790 "color: white; "
791 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
792 "" stringByAppendingString:(IsWild_
793 ? @"font-size: 11px; "
794 : @"font-size: 9px; "
795 )]);
796
797 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
798 datestyle = [datestyle stringByAppendingString:style];
799 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
800 daystyle = [daystyle stringByAppendingString:style];
801
802 float width([self bounds].size.width);
803 float leeway(10);
804 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
805 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
806
807 unsigned base0(IsWild_ ? 89 : 70);
808 if ($GSFontGetUseLegacyFontMetrics())
809 base0 = base0 + 1;
810 unsigned base1(IsWild_ ? 18 : 16);
811
812 if (Four_) {
813 ++base0;
814 ++base1;
815 }
816
817 [(NSString *)date drawAtPoint:CGPointMake(
818 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
819 ) withStyle:datestyle];
820
821 [(NSString *)day drawAtPoint:CGPointMake(
822 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
823 ) withStyle:daystyle];
824
825 CFRelease(date);
826 CFRelease(day);
827 }
828
829 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
830 void $setBarStyle$_(NSString *name, int &style) {
831 if (Debug_)
832 NSLog(@"WB:Debug:%@Style:%d", name, style);
833 NSNumber *number = nil;
834 if (number == nil)
835 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
836 if (number == nil)
837 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
838 if (number != nil) {
839 style = [number intValue];
840 if (Debug_)
841 NSLog(@"WB:Debug:%@Style=%d", name, style);
842 }
843 }
844
845 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
846 $setBarStyle$_(@"Toolbar", style);
847 return MSOldCall(style);
848 }
849
850 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
851 $setBarStyle$_(@"NavigationBar", style);
852 return MSOldCall(style);
853 }
854 // }}}
855
856 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
857 [[self superview] setBackgroundColor:[UIColor clearColor]];
858 _SBButtonBar$didMoveToSuperview(self, sel);
859 }
860
861 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
862 [[self superview] setBackgroundColor:[UIColor clearColor]];
863 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
864 }
865
866 static NSArray *Wallpapers_;
867 static bool Papered_;
868 static bool Docked_;
869 static NSString *WallpaperFile_;
870 static UIImageView *WallpaperImage_;
871 static UIWebDocumentView *WallpaperPage_;
872 static NSURL *WallpaperURL_;
873
874 #define _release(object) \
875 do if (object != nil) { \
876 [object release]; \
877 object = nil; \
878 } while (false)
879
880 static UIImage *$getImage$(NSString *path) {
881 UIImage *image([UIImage imageWithContentsOfFile:path]);
882
883 unsigned scale($getScale$(path));
884 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
885 [image setScale:scale];
886
887 return image;
888 }
889
890 static UIImage *$getDefaultDesktopImage$() {
891 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
892 return $getImage$(path);
893 return nil;
894 }
895
896 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
897 return $getDefaultDesktopImage$() ?: MSOldCall();
898 }
899
900 MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
901 return $getDefaultDesktopImage$() ?: MSOldCall();
902 }
903
904 MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
905 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
906 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
907 if (UIImage *image = $getDefaultDesktopImage$()) {
908 [self setImage:image];
909 return;
910 }
911
912 break;
913 }
914
915 MSOldCall();
916 }
917
918 // %hook -[SBUIController init] {{{
919 MSInstanceMessageHook0(id, SBUIController, init) {
920 self = MSOldCall();
921 if (self == nil)
922 return nil;
923
924 NSString *paper($getTheme$(Wallpapers_));
925 if (paper != nil)
926 paper = [paper stringByDeletingLastPathComponent];
927
928 {
929 size_t size;
930 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
931 char *machine = new char[size];
932
933 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
934 perror("sysctlbyname(\"hw.machine\", ?)");
935 delete [] machine;
936 machine = NULL;
937 }
938
939 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
940 }
941
942 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
943
944 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
945 [Info_ setObject:[NSNumber numberWithBool:(
946 !(paper != nil || GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"))) ||
947 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
948 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
949 )] forKey:@"UndockedIconLabels"];
950
951 if (Debug_)
952 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
953
954 if (paper != nil) {
955 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
956 if (&_wallpaperView != NULL) {
957 [_wallpaperView removeFromSuperview];
958 [_wallpaperView release];
959 _wallpaperView = nil;
960 }
961 }
962
963 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
964 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
965
966 UIView **player;
967 if (&_contentLayer != NULL)
968 player = &_contentLayer;
969 else if (&_contentView != NULL)
970 player = &_contentView;
971 else
972 player = NULL;
973 UIView *layer(player == NULL ? nil : *player);
974
975 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
976 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
977 [window setContentView:content];
978
979 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
980 [window setBackgroundColor:[_window backgroundColor]];
981 [_window setBackgroundColor:[UIColor clearColor]];
982
983 [window setLevel:-1000];
984 [window setHidden:NO];
985
986 /*if (player != NULL)
987 *player = content;*/
988
989 [content setBackgroundColor:[layer backgroundColor]];
990 [layer setBackgroundColor:[UIColor clearColor]];
991
992 UIView *indirect;
993 if (!SummerBoard_ || !IsWild_)
994 indirect = content;
995 else {
996 CGRect bounds([content bounds]);
997 bounds.origin.y = -30;
998 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
999 [content addSubview:indirect];
1000 [indirect zoomToScale:2.4];
1001 }
1002
1003 _release(WallpaperFile_);
1004 _release(WallpaperImage_);
1005 _release(WallpaperPage_);
1006 _release(WallpaperURL_);
1007
1008 if (paper != nil) {
1009 NSArray *themes([NSArray arrayWithObject:paper]);
1010
1011 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1012 #if UseAVController
1013 NSError *error;
1014
1015 static AVController *controller_(nil);
1016 if (controller_ == nil) {
1017 AVQueue *queue([AVQueue avQueue]);
1018 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1019 }
1020
1021 AVQueue *queue([controller_ queue]);
1022
1023 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1024 [controller_ setLayer:[video _layer]];
1025
1026 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1027 [queue appendItem:item error:&error];
1028
1029 [controller_ play:&error];
1030 #elif UseMPMoviePlayerController
1031 NSURL *url([NSURL fileURLWithPath:path]);
1032 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1033 controller.movieControlMode = MPMovieControlModeHidden;
1034 [controller play];
1035 #else
1036 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1037 [video setMovieWithPath:path];
1038 [video setRepeatMode:1];
1039 [video setRepeatGap:-1];
1040 [video playFromBeginning];;
1041 #endif
1042
1043 [indirect addSubview:video];
1044 }
1045
1046 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1047 if (UIImage *image = $getImage$(path)) {
1048 WallpaperFile_ = [path retain];
1049 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1050 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1051 [WallpaperImage_ setAlpha:[number floatValue]];
1052 [indirect addSubview:WallpaperImage_];
1053 }
1054 }
1055
1056 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1057 CGRect bounds = [indirect bounds];
1058
1059 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1060 [view setAutoresizes:true];
1061
1062 WallpaperPage_ = [view retain];
1063 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1064
1065 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1066
1067 [view setBackgroundColor:[UIColor clearColor]];
1068 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1069 [view setDrawsBackground:NO];
1070 [[view webView] setDrawsBackground:NO];
1071
1072 [indirect addSubview:view];
1073 }
1074 }
1075
1076 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1077 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1078 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1079 if ([Manager_ fileExistsAtPath:html]) {
1080 CGRect bounds = [indirect bounds];
1081
1082 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1083 [view setAutoresizes:true];
1084
1085 NSURL *url = [NSURL fileURLWithPath:html];
1086 [view loadRequest:[NSURLRequest requestWithURL:url]];
1087
1088 [view setBackgroundColor:[UIColor clearColor]];
1089 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1090 [view setDrawsBackground:NO];
1091 [[view webView] setDrawsBackground:NO];
1092
1093 [indirect addSubview:view];
1094 }
1095 }
1096
1097 return self;
1098 }
1099 // }}}
1100
1101 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1102 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1103 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1104
1105 if (path != nil && _backgroundView != nil)
1106 path = nil;
1107
1108 _SBAwayView$updateDesktopImage$(self, sel, image);
1109
1110 if (path != nil) {
1111 CGRect bounds = [self bounds];
1112
1113 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1114 [view setAutoresizes:true];
1115
1116 if (WallpaperPage_ != nil)
1117 [WallpaperPage_ release];
1118 WallpaperPage_ = [view retain];
1119
1120 if (WallpaperURL_ != nil)
1121 [WallpaperURL_ release];
1122 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1123
1124 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1125
1126 [[view webView] setDrawsBackground:false];
1127 [view setBackgroundColor:[UIColor clearColor]];
1128
1129 [self insertSubview:view aboveSubview:_backgroundView];
1130 }
1131 }
1132
1133 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1134 extern "C" CGColorRef CGGStateGetFillColor(void *);
1135 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1136 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1137
1138 /* WBTimeLabel {{{ */
1139 @interface WBTimeLabel : NSProxy {
1140 NSString *time_;
1141 _transient SBStatusBarTimeView *view_;
1142 }
1143
1144 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1145
1146 @end
1147
1148 @implementation WBTimeLabel
1149
1150 - (void) dealloc {
1151 [time_ release];
1152 [super dealloc];
1153 }
1154
1155 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1156 time_ = [time retain];
1157 view_ = view;
1158 return self;
1159 }
1160
1161 - (NSString *) description {
1162 return time_;
1163 }
1164
1165 WBDelegate(time_)
1166
1167 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1168 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1169 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1170
1171 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1172 "font-family: Helvetica; "
1173 "font-weight: bold; "
1174 "font-size: 14px; "
1175 "color: %@; "
1176 "%@", _mode ? @"white" : @"black", custom]];
1177
1178 return CGSizeZero;
1179 }
1180
1181 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1182 }
1183
1184 @end
1185 /* }}} */
1186 /* WBBadgeLabel {{{ */
1187 @interface WBBadgeLabel : NSProxy {
1188 NSString *badge_;
1189 }
1190
1191 - (id) initWithBadge:(NSString *)badge;
1192 - (NSString *) description;
1193
1194 @end
1195
1196 @implementation WBBadgeLabel
1197
1198 - (void) dealloc {
1199 [badge_ release];
1200 [super dealloc];
1201 }
1202
1203 - (id) initWithBadge:(NSString *)badge {
1204 badge_ = [badge retain];
1205 return self;
1206 }
1207
1208 - (NSString *) description {
1209 return [badge_ description];
1210 }
1211
1212 WBDelegate(badge_)
1213
1214 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1215 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1216 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1217 "font-family: Helvetica; "
1218 "font-weight: bold; "
1219 "font-size: 17px; "
1220 "color: white; "
1221 "%@", custom]];
1222
1223 return CGSizeZero;
1224 }
1225
1226 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1227 }
1228
1229 @end
1230 /* }}} */
1231
1232 // IconAlpha {{{
1233 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
1234 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1235 alpha = [number floatValue];
1236 return MSOldCall(alpha);
1237 }
1238
1239 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
1240 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1241 alpha = [number floatValue];
1242 return MSOldCall(alpha);
1243 }
1244
1245 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1246 if ((self = MSOldCall()) != nil) {
1247 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1248 // XXX: note: this is overridden above, which is silly
1249 float alpha([number floatValue]);
1250 [self setIconImageAlpha:alpha];
1251 [self setIconLabelAlpha:alpha];
1252 }
1253 } return self;
1254 }
1255
1256 MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
1257 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1258 alpha = [number floatValue];
1259 return MSOldCall(alpha);
1260 }
1261 // }}}
1262
1263 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1264 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1265 id &_badge(MSHookIvar<id>(self, "_badge"));
1266 if (_badge != nil)
1267 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1268 _badge = label;
1269 } return self;
1270 }
1271
1272 void SBStatusBarController$setStatusBarMode(int &mode) {
1273 if (Debug_)
1274 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1275 if (mode < 100) // 104:hidden 105:glowing
1276 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1277 mode = [number intValue];
1278 }
1279
1280 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1281 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1282 SBStatusBarController$setStatusBarMode(mode);
1283 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1284 }*/
1285
1286 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1287 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1288 SBStatusBarController$setStatusBarMode(mode);
1289 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1290 }
1291
1292 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) {
1293 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1294 SBStatusBarController$setStatusBarMode(mode);
1295 //NSLog(@"mode=%u", mode);
1296 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1297 }
1298
1299 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1300 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1301 mode = [number intValue];
1302 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1303 }*/
1304
1305 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1306 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1307 if (Debug_)
1308 NSLog(@"operatorNameStyle= %@", style);
1309 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1310 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1311 return style;
1312 }
1313
1314 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1315 if (Debug_)
1316 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1317 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1318 }
1319
1320 // XXX: replace this with [SBStatusBarTimeView tile]
1321 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1322 id &_time(MSHookIvar<id>(self, "_time"));
1323 if (_time != nil && [_time class] != [WBTimeLabel class])
1324 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1325 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1326 }
1327
1328 @interface UIView (WinterBoard)
1329 - (bool) wb$isWBImageView;
1330 - (void) wb$logHierarchy;
1331 @end
1332
1333 @implementation UIView (WinterBoard)
1334
1335 - (bool) wb$isWBImageView {
1336 return false;
1337 }
1338
1339 - (void) wb$logHierarchy {
1340 WBLogHierarchy(self);
1341 }
1342
1343 @end
1344
1345 @interface WBImageView : UIImageView {
1346 }
1347
1348 - (bool) wb$isWBImageView;
1349 - (void) wb$updateFrame;
1350 @end
1351
1352 @implementation WBImageView
1353
1354 - (bool) wb$isWBImageView {
1355 return true;
1356 }
1357
1358 - (void) wb$updateFrame {
1359 CGRect frame([self frame]);
1360 frame.origin.y = 0;
1361
1362 for (UIView *view(self); ; ) {
1363 view = [view superview];
1364 if (view == nil)
1365 break;
1366 frame.origin.y -= [view frame].origin.y;
1367 }
1368
1369 [self setFrame:frame];
1370 }
1371
1372 @end
1373
1374 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1375 NSArray *subviews([self subviews]);
1376 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1377 if (view != nil && [view wb$isWBImageView])
1378 [view wb$updateFrame];
1379 _SBIconList$setFrame$(self, sel, frame);
1380 }
1381
1382 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1383 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1384 NSArray *lists([_iconModel iconLists]);
1385
1386 for (unsigned i(0), e([lists count]); i != e; ++i)
1387 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]])) {
1388 SBIconList *list([lists objectAtIndex:i]);
1389 NSArray *subviews([list subviews]);
1390
1391 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1392 if (view == nil || ![view wb$isWBImageView]) {
1393 view = [[[WBImageView alloc] init] autorelease];
1394 [list insertSubview:view atIndex:0];
1395 }
1396
1397 UIImage *image([UIImage imageWithContentsOfFile:path]);
1398
1399 CGRect frame([view frame]);
1400 frame.size = [image size];
1401 [view setFrame:frame];
1402
1403 [view setImage:image];
1404 [view wb$updateFrame];
1405 }
1406
1407 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1408 }
1409
1410 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1411 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1412 if (self != nil)
1413 [self setClipsToBounds:NO];
1414 return self;
1415 }
1416
1417 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1418 id &_label(MSHookIvar<id>(self, "_label"));
1419 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1420 docked = true;
1421
1422 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1423 [_label setInDock:docked];
1424
1425 _SBIconLabel$setInDock$(self, sel, docked);
1426 [self setNeedsDisplay];
1427 }
1428
1429 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1430 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1431 }
1432
1433 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1434 _SBDockIconListView$setFrame$(self, sel, frame);
1435 }
1436
1437 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1438 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1439 NSString *identifier = [self bundleIdentifier];
1440 NSLocale *locale = [NSLocale currentLocale];
1441 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1442 if (Debug_)
1443 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1444 NSString *file = table == nil ? @"Localizable" : table;
1445 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1446 NSDictionary *strings;
1447 if ((strings = [Strings_ objectForKey:name]) != nil) {
1448 if (static_cast<id>(strings) != [NSNull null]) strings:
1449 if (NSString *value = [strings objectForKey:key])
1450 return value;
1451 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1452 language, file
1453 ], self, false)) {
1454 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1455 [Strings_ setObject:[strings autorelease] forKey:name];
1456 goto strings;
1457 } else goto null;
1458 } else null:
1459 [Strings_ setObject:[NSNull null] forKey:name];
1460 return MSOldCall(key, value, table);
1461 }
1462 // }}}
1463 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1464 MSClassHook(WebCoreFrameBridge)
1465
1466 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1467 if (node == nil)
1468 return CGSizeZero;
1469 void **core(reinterpret_cast<void **>([node _node]));
1470 if (core == NULL || core[6] == NULL)
1471 return CGSizeZero;
1472 return MSOldCall(node, width);
1473 }
1474 // }}}
1475
1476 MSInstanceMessageHook1(void, SBIconLabel, drawRect, CGRect, rect) {
1477 CGRect bounds = [self bounds];
1478
1479 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1480
1481 int docked;
1482 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1483 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1484
1485 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1486
1487 NSString *style = [NSString stringWithFormat:@""
1488 "font-family: Helvetica; "
1489 "font-weight: bold; "
1490 "color: %@; %@"
1491 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1492 ? @"font-size: 12px; "
1493 : @"font-size: 11px; "
1494 )];
1495
1496 if (IsWild_)
1497 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1498 else if (docked)
1499 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1500
1501 bool ellipsis(false);
1502 float max = [self frame].size.width - 11, width;
1503 width:
1504 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
1505
1506 if (width > max) {
1507 size_t length([label length]);
1508 float spacing((width - max) / (length - 1));
1509
1510 if (spacing > 1.25) {
1511 ellipsis = true;
1512 label = [label substringToIndex:(length - 1)];
1513 goto width;
1514 }
1515
1516 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
1517 }
1518
1519 if (ellipsis)
1520 label = [label stringByAppendingString:@"..."];
1521
1522 if (NSString *custom = [Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")])
1523 style = [style stringByAppendingString:custom];
1524
1525 CGSize size = [label sizeWithStyle:style forWidth:bounds.size.width];
1526 [label drawAtPoint:CGPointMake((bounds.size.width - size.width) / 2, 0) withStyle:style];
1527 }
1528
1529 // ChatKit {{{
1530 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1531 MSOldCall(balloon);
1532 [balloon setBackgroundColor:[UIColor clearColor]];
1533 }
1534
1535 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1536 MSOldCall([UIColor clearColor]);
1537 }
1538
1539 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1540 if ((self = MSOldCall(style, reuse)) != nil) {
1541 [self setBackgroundColor:[UIColor clearColor]];
1542 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1543 } return self;
1544 }
1545
1546 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1547 if ((self = MSOldCall(style, reuse)) != nil) {
1548 [self setBackgroundColor:[UIColor clearColor]];
1549 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1550 } return self;
1551 }
1552
1553 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1554 if ((self = MSOldCall(style, reuse)) != nil) {
1555 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1556 [_label setBackgroundColor:[UIColor clearColor]];
1557 } return self;
1558 }
1559
1560 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1561 MSOldCall(UITableViewCellSeparatorStyleNone);
1562 }
1563
1564 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1565 if ((self = MSOldCall(frame, style)) != nil) {
1566 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1567 } return self;
1568 }
1569
1570 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1571 MSOldCall();
1572
1573 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1574 if (UIImage *image = $getImage$(path)) {
1575 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1576 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1577 UIView *table;
1578 if (&_transcriptTable != NULL)
1579 table = _transcriptTable;
1580 else if (&_transcriptLayer != NULL)
1581 table = _transcriptLayer;
1582 else
1583 table = nil;
1584
1585 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1586 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1587
1588 if (table == nil)
1589 [placard insertSubview:background atIndex:0];
1590 else {
1591 [table setBackgroundColor:[UIColor clearColor]];
1592 [placard insertSubview:background belowSubview:table];
1593 }
1594 }
1595 }
1596 // }}}
1597
1598 // %hook _UIImageWithName() {{{
1599 MSHook(UIImage *, _UIImageWithName, NSString *name) {
1600 if (Debug_)
1601 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
1602 if (name == nil)
1603 return nil;
1604
1605 int identifier;
1606 bool packed;
1607
1608 if (_UIPackedImageTableGetIdentifierForName != NULL)
1609 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1610 else if (_UISharedImageNameGetIdentifier != NULL) {
1611 identifier = _UISharedImageNameGetIdentifier(name);
1612 packed = identifier != -1;
1613 } else {
1614 identifier = -1;
1615 packed = false;
1616 }
1617
1618 if (Debug_)
1619 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
1620
1621 if (!packed)
1622 return __UIImageWithName(name);
1623 else {
1624 NSNumber *key([NSNumber numberWithInt:identifier]);
1625 UIImage *image([UIImages_ objectForKey:key]);
1626 if (image != nil)
1627 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
1628 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1629 image = $getImage$(path);
1630 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1631 if (image != nil)
1632 return image;
1633
1634 image = __UIImageWithName(name);
1635
1636 if (UIDebug_) {
1637 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1638 if (![Manager_ fileExistsAtPath:path])
1639 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1640 }
1641
1642 return image;
1643 }
1644 }
1645 // }}}
1646 // %hook _UIImageWithNameInDomain() {{{
1647 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
1648 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1649 UIImage *image([PathImages_ objectForKey:key]);
1650 if (image != nil)
1651 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
1652 if (Debug_)
1653 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
1654 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
1655 image = $getImage$(path);
1656 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1657 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
1658 }
1659 // }}}
1660
1661 // %hook GSFontCreateWithName() {{{
1662 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
1663 if (Debug_)
1664 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
1665 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1666 name = [font UTF8String];
1667 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1668 // size *= [scale floatValue];
1669 return _GSFontCreateWithName(name, traits, size);
1670 }
1671 // }}}
1672
1673 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1674 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1675
1676 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
1677
1678 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
1679 if (Debug_)
1680 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
1681 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
1682 if (Debug_)
1683 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1684
1685 if (value) {
1686 NSString *path = [NSString stringWithUTF8String:a1];
1687 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1688 NSString *file = [path substringFromIndex:31];
1689 for (NSString *theme in Themes_) {
1690 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1691 if ([Manager_ fileExistsAtPath:path]) {
1692 strcpy(a1, [path UTF8String]);
1693 continue;
1694 }
1695 }
1696 }
1697 }
1698 return value;
1699 }
1700
1701 static void ChangeWallpaper(
1702 CFNotificationCenterRef center,
1703 void *observer,
1704 CFStringRef name,
1705 const void *object,
1706 CFDictionaryRef info
1707 ) {
1708 if (Debug_)
1709 NSLog(@"WB:Debug:ChangeWallpaper!");
1710
1711 UIImage *image;
1712 if (WallpaperFile_ != nil) {
1713 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
1714 if (image != nil)
1715 image = [image autorelease];
1716 } else image = nil;
1717
1718 if (WallpaperImage_ != nil)
1719 [WallpaperImage_ setImage:image];
1720 if (WallpaperPage_ != nil)
1721 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1722
1723 }
1724
1725 #define WBRename(name, sel, imp) \
1726 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
1727
1728 template <typename Type_>
1729 static void msset(Type_ &function, MSImageRef image, const char *name) {
1730 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1731 }
1732
1733 template <typename Type_>
1734 static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1735 struct nlist &name(nl[index]);
1736 uintptr_t value(name.n_value);
1737 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1738 value |= 0x00000001;
1739 function = reinterpret_cast<Type_>(value);
1740 }
1741
1742 template <typename Type_>
1743 static void dlset(Type_ &function, const char *name) {
1744 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
1745 }
1746
1747 // %hook CGImageReadCreateWithFile() {{{
1748 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1749 if (Debug_)
1750 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
1751 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1752 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1753 [pool release];
1754 return value;
1755 }
1756 // }}}
1757
1758 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
1759 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1760 if (style == nil || [style length] == 0)
1761 style = @"font-family: Helvetica; font-size: 12px";
1762 return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
1763 }
1764
1765 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
1766 if (style == nil || [style length] == 0)
1767 style = @"font-family: Helvetica; font-size: 12px";
1768 return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width];
1769 }
1770
1771 static void SBInitialize() {
1772 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
1773 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
1774
1775 if (SummerBoard_) {
1776 WBRename(SBApplication, pathForIcon, pathForIcon);
1777 WBRename(SBApplicationIcon, icon, icon);
1778 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1779 }
1780
1781 WBRename(SBBookmarkIcon, icon, icon);
1782 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1783 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1784 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1785 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
1786
1787 WBRename(SBWidgetApplicationIcon, icon, icon);
1788
1789 WBRename(SBDockIconListView, setFrame:, setFrame$);
1790 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
1791
1792 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
1793 WBRename(SBIconLabel, setInDock:, setInDock$);
1794
1795 WBRename(SBIconList, setFrame:, setFrame$);
1796
1797 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
1798 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
1799 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
1800 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
1801
1802 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
1803 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
1804 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
1805
1806 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
1807
1808 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
1809 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
1810 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
1811 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
1812 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
1813 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
1814 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
1815 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
1816 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
1817
1818 if (SummerBoard_)
1819 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
1820 }
1821
1822 MSInitialize {
1823 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
1824
1825 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
1826 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
1827
1828 Manager_ = [[NSFileManager defaultManager] retain];
1829 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
1830
1831 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
1832
1833 // Load Settings.plist {{{
1834 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
1835 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
1836 SummerBoard_ = [value boolValue];
1837 if (NSNumber *value = [settings objectForKey:@"Debug"])
1838 Debug_ = [value boolValue];
1839
1840 NSArray *themes([settings objectForKey:@"Themes"]);
1841 if (themes == nil)
1842 if (NSString *theme = [settings objectForKey:@"Theme"])
1843 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
1844 theme, @"Name",
1845 [NSNumber numberWithBool:true], @"Active",
1846 nil]];
1847
1848 if (themes != nil)
1849 for (NSDictionary *theme in themes) {
1850 NSNumber *active([theme objectForKey:@"Active"]);
1851 if (![active boolValue])
1852 continue;
1853
1854 NSString *name([theme objectForKey:@"Name"]);
1855 if (name == nil)
1856 continue;
1857
1858 NSString *theme(nil);
1859
1860 #define testForTheme(format...) \
1861 if (theme == nil) { \
1862 NSString *path = [NSString stringWithFormat:format]; \
1863 if ([Manager_ fileExistsAtPath:path]) { \
1864 [Themes_ addObject:path]; \
1865 continue; \
1866 } \
1867 }
1868
1869 testForTheme(@"/Library/Themes/%@.theme", name)
1870 testForTheme(@"/Library/Themes/%@", name)
1871 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
1872
1873 }
1874 }
1875 // }}}
1876 // Merge Info.plist {{{
1877 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1878
1879 for (NSString *theme in Themes_)
1880 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
1881 for (NSString *key in [info allKeys])
1882 if ([Info_ objectForKey:key] == nil)
1883 [Info_ setObject:[info objectForKey:key] forKey:key];
1884 // }}}
1885
1886 // AudioToolbox {{{
1887 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
1888 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
1889 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
1890 }
1891 // }}}
1892 // GraphicsServices {{{
1893 if (true) {
1894 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
1895 }
1896 // }}}
1897 // ImageIO {{{
1898 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
1899 void *(*CGImageReadCreateWithFile)(NSString *, int);
1900 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
1901 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
1902 }
1903 // }}}
1904 // SpringBoard {{{
1905 if (SpringBoard_) {
1906 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
1907 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]);
1908
1909 CFNotificationCenterAddObserver(
1910 CFNotificationCenterGetDarwinNotifyCenter(),
1911 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
1912 );
1913
1914 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
1915 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
1916 if (MediaPlayer != nil)
1917 [MediaPlayer load];
1918
1919 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
1920 $MPVideoView = objc_getClass("MPVideoView");
1921 }
1922
1923 SBInitialize();
1924 }
1925 // }}}
1926 // UIKit {{{
1927 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
1928 struct nlist nl[6];
1929 memset(nl, 0, sizeof(nl));
1930 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
1931 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
1932 nl[2].n_un.n_name = (char *) "__UIKitBundle";
1933 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
1934 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
1935 nlist(UIKit, nl);
1936
1937 nlset(_UIApplicationImageWithName, nl, 0);
1938 nlset(_UIImageWithNameInDomain, nl, 1);
1939 nlset(_UIKitBundle, nl, 2);
1940 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
1941 nlset(_UISharedImageNameGetIdentifier, nl, 4);
1942
1943 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
1944 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
1945 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
1946 }
1947 // }}}
1948
1949 if (Debug_ && [Manager_ fileExistsAtPath:@"/tmp/UIImages"])
1950 UIDebug_ = true;
1951
1952 [pool release];
1953 }