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