]> git.saurik.com Git - winterboard.git/blob - Library.mm
dbc1995f2dab7b018ce36d21bcc6d0c27e409edc
[winterboard.git] / Library.mm
1 /* WinterBoard - Theme Manager for the iPhone
2 * Copyright (C) 2008-2014 Jay Freeman (saurik)
3 */
4
5 /* GNU Lesser General Public License, Version 3 {{{ */
6 /*
7 * WinterBoard is free software: you can redistribute it and/or modify it under
8 * the terms of the GNU Lesser General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
11 *
12 * WinterBoard is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 * License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with WinterBoard. If not, see <http://www.gnu.org/licenses/>.
19 **/
20 /* }}} */
21
22 #include <sys/time.h>
23
24 struct timeval _ltv;
25 bool _itv;
26
27 #define _trace() do { \
28 struct timeval _ctv; \
29 gettimeofday(&_ctv, NULL); \
30 if (!_itv) { \
31 _itv = true; \
32 _ltv = _ctv; \
33 } \
34 NSLog(@"%lu.%.6u[%f]:WB:_trace()@%s:%u[%s]\n", \
35 _ctv.tv_sec, _ctv.tv_usec, \
36 (_ctv.tv_sec - _ltv.tv_sec) + (_ctv.tv_usec - _ltv.tv_usec) / 1000000.0, \
37 __FILE__, __LINE__, __FUNCTION__\
38 ); \
39 _ltv = _ctv; \
40 } while (false)
41
42 #define _transient
43
44 #import <CoreFoundation/CoreFoundation.h>
45 #import <Foundation/Foundation.h>
46 #import <CoreGraphics/CoreGraphics.h>
47 #import <ImageIO/CGImageSource.h>
48
49 #import <Celestial/AVController.h>
50 #import <Celestial/AVItem.h>
51 #import <Celestial/AVQueue.h>
52
53 #include <substrate.h>
54
55 #import <UIKit/UIKit.h>
56
57 #import <SpringBoard/SBApplication.h>
58 #import <SpringBoard/SBApplicationIcon.h>
59 #import <SpringBoard/SBAppWindow.h>
60 #import <SpringBoard/SBAwayView.h>
61 #import <SpringBoard/SBBookmarkIcon.h>
62 #import <SpringBoard/SBButtonBar.h>
63 #import <SpringBoard/SBCalendarIconContentsView.h>
64 #import <SpringBoard/SBIconController.h>
65 #import <SpringBoard/SBIconLabel.h>
66 #import <SpringBoard/SBIconList.h>
67 #import <SpringBoard/SBIconModel.h>
68 #import <SpringBoard/SBImageCache.h>
69 // XXX: #import <SpringBoard/SBSearchView.h>
70 #import <SpringBoard/SBSearchTableViewCell.h>
71 #import <SpringBoard/SBStatusBarContentsView.h>
72 #import <SpringBoard/SBStatusBarController.h>
73 #import <SpringBoard/SBStatusBarOperatorNameView.h>
74 #import <SpringBoard/SBStatusBarTimeView.h>
75 #import <SpringBoard/SBUIController.h>
76 #import <SpringBoard/SBWidgetApplicationIcon.h>
77
78 #import <MobileSMS/mSMSMessageTranscriptController.h>
79
80 #import <MediaPlayer/MPMoviePlayerController.h>
81 #import <MediaPlayer/MPVideoView.h>
82 #import <MediaPlayer/MPVideoView-PlaybackControl.h>
83
84 #import <CoreGraphics/CGGeometry.h>
85
86 #import <ChatKit/CKMessageCell.h>
87
88 #include <sys/sysctl.h>
89
90 #include "WBMarkup.h"
91
92 static void (*$objc_setAssociatedObject)(id object, void *key, id value, objc_AssociationPolicy policy);
93 static id (*$objc_getAssociatedObject)(id object, void *key);
94 static void (*$objc_removeAssociatedObjects)(id object);
95
96 @protocol WinterBoard
97 - (void *) _node;
98 @end
99
100 Class $MPMoviePlayerController;
101 Class $MPVideoView;
102
103 MSClassHook(NSBundle)
104 MSClassHook(NSString)
105
106 MSClassHook(UIImage)
107 MSMetaClassHook(UIImage)
108 MSClassHook(UINavigationBar)
109 MSClassHook(UISharedArtwork)
110 MSClassHook(UIToolbar)
111 MSClassHook(UIStatusBarTimeItemView)
112 MSClassHook(UIWebDocumentView)
113
114 MSClassHook(CKBalloonView)
115 MSClassHook(CKMessageCell)
116 MSClassHook(CKTimestampView)
117 MSClassHook(CKTranscriptCell)
118 MSClassHook(CKTranscriptController)
119 MSClassHook(CKTranscriptHeaderView)
120 MSClassHook(CKTranscriptTableView)
121
122 MSClassHook(SBApplication)
123 MSClassHook(SBApplicationIcon)
124 MSClassHook(SBAwayView)
125 MSClassHook(SBBookmarkIcon)
126 MSClassHook(SBButtonBar)
127 MSClassHook(SBCalendarApplicationIcon)
128 MSClassHook(SBCalendarIconContentsView)
129 MSClassHook(SBDockIconListView)
130 MSClassHook(SBIcon)
131 MSClassHook(SBIconAccessoryImage)
132 MSMetaClassHook(SBIconAccessoryImage)
133 MSClassHook(SBIconBadge)
134 MSClassHook(SBIconBadgeFactory)
135 MSClassHook(SBIconBadgeImage)
136 MSClassHook(SBIconBadgeView)
137 MSMetaClassHook(SBIconBadgeView)
138 MSClassHook(SBIconContentView)
139 MSClassHook(SBIconController)
140 MSClassHook(SBIconLabel)
141 MSClassHook(SBIconLabelImage)
142 MSMetaClassHook(SBIconLabelImage)
143 MSClassHook(SBIconLabelImageParameters)
144 MSClassHook(SBIconList)
145 MSClassHook(SBIconModel)
146 MSClassHook(SBIconView)
147 MSMetaClassHook(SBIconView)
148 //MSClassHook(SBImageCache)
149 MSClassHook(SBSearchView)
150 MSClassHook(SBSearchTableViewCell)
151 MSClassHook(SBSlidingAlertDisplay)
152 MSClassHook(SBStatusBarContentsView)
153 MSClassHook(SBStatusBarController)
154 MSClassHook(SBStatusBarOperatorNameView)
155 MSClassHook(SBStatusBarTimeView)
156 MSClassHook(SBUIController)
157 MSClassHook(SBWallpaperView)
158 MSClassHook(SBWidgetApplicationIcon)
159
160 extern "C" void WKSetCurrentGraphicsContext(CGContextRef);
161
162 static struct MSFixClass { MSFixClass() {
163 $UIWebDocumentView = objc_getClass("UIWebBrowserView") ?: $UIWebDocumentView;
164 $SBIcon = objc_getClass("SBIconView") ?: $SBIcon;
165
166 if ($SBIconList == nil)
167 $SBIconList = objc_getClass("SBIconListView");
168 if ($CKTranscriptController == nil)
169 $CKTranscriptController = objc_getClass("mSMSMessageTranscriptController");
170 } } MSFixClass;
171
172 static bool IsWild_;
173 static bool Four_($SBDockIconListView != nil);
174
175 @interface NSObject (wb$SBIconAccessoryImage)
176 + (Class) _imageClassForIcon:(SBIcon *)icon location:(int)location;
177 @end
178
179 @interface NSDictionary (WinterBoard)
180 - (UIColor *) wb$colorForKey:(NSString *)key;
181 - (BOOL) wb$boolForKey:(NSString *)key;
182 @end
183
184 @implementation NSDictionary (WinterBoard)
185
186 - (UIColor *) wb$colorForKey:(NSString *)key {
187 NSString *value = [self objectForKey:key];
188 if (value == nil)
189 return nil;
190 /* XXX: incorrect */
191 return nil;
192 }
193
194 - (BOOL) wb$boolForKey:(NSString *)key {
195 if (NSString *value = [self objectForKey:key])
196 return [value boolValue];
197 return false;
198 }
199
200 @end
201
202 static BOOL (*_GSFontGetUseLegacyFontMetrics)();
203 #define $GSFontGetUseLegacyFontMetrics() \
204 (_GSFontGetUseLegacyFontMetrics == NULL ? YES : _GSFontGetUseLegacyFontMetrics())
205
206 static bool Debug_ = false;
207 static bool UIDebug_ = false;
208 static bool Engineer_ = false;
209 static bool SummerBoard_ = false;
210 static bool SpringBoard_;
211
212 static UIImage *(*_UIApplicationImageWithName)(NSString *name);
213 static UIImage *(*_UIImageWithNameInDomain)(NSString *name, NSString *domain);
214 static UIImage *(*_UIImageWithNameUsingCurrentIdiom)(NSString *name);
215 static UIImage *(*_UIImageWithDeviceSpecificName)(NSString *name);
216 static NSBundle *(*_UIKitBundle)();
217
218 static NSMutableDictionary *Images_ = [[NSMutableDictionary alloc] initWithCapacity:64];
219 static NSMutableDictionary *Cache_ = [[NSMutableDictionary alloc] initWithCapacity:64];
220 static NSMutableDictionary *Strings_ = [[NSMutableDictionary alloc] initWithCapacity:0];
221 static NSMutableDictionary *Bundles_ = [[NSMutableDictionary alloc] initWithCapacity:2];
222
223 static NSFileManager *Manager_;
224 static NSMutableArray *Themes_;
225
226 static NSDictionary *English_;
227 static NSMutableDictionary *Info_;
228
229 // $getTheme$() {{{
230 static NSMutableDictionary *Themed_ = [[NSMutableDictionary alloc] initWithCapacity:128];
231
232 static unsigned Scale_ = 0;
233
234 static unsigned $getScale$(NSString *path) {
235 NSString *name(path);
236
237 #define StripName(strip) \
238 if ([name hasSuffix:@ strip]) \
239 name = [name substringWithRange:NSMakeRange(0, [name length] - sizeof(strip) - 1)];
240
241 StripName(".png");
242 StripName(".jpg");
243 StripName("~iphone");
244 StripName("~ipad");
245
246 return [name hasSuffix:@"@2x"] ? 2 : 1;
247 }
248
249 static NSArray *$useScale$(NSArray *files, bool use = true) {
250 if (use && Scale_ == 0) {
251 UIScreen *screen([UIScreen mainScreen]);
252 if ([screen respondsToSelector:@selector(scale)])
253 Scale_ = [screen scale];
254 else
255 Scale_ = 1;
256 }
257
258 NSString *idiom(IsWild_ ? @"ipad" : @"iphone");
259
260 NSMutableArray *scaled([NSMutableArray arrayWithCapacity:([files count] * 4)]);
261
262 for (NSString *file in files) {
263 NSString *base([file stringByDeletingPathExtension]);
264 NSString *extension([file pathExtension]);
265
266 if (use) {
267 if (Scale_ == 2) {
268 [scaled addObject:[NSString stringWithFormat:@"%@@2x~%@.%@", base, idiom, extension]];
269 [scaled addObject:[NSString stringWithFormat:@"%@@2x.%@", base, extension]];
270 }
271
272 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
273
274 // if (!IsWild_) <- support old themes
275 [scaled addObject:file];
276 } else if ([base hasSuffix: @"@2x"]) {
277 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
278 [scaled addObject:file];
279
280 // XXX: this actually can't be used, as the person loading the file doesn't realize that the @2x changed
281 /*NSString *rest([base substringWithRange:NSMakeRange(0, [base length] - 3)]);
282 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", rest, idiom, extension]];
283 [scaled addObject:[rest stringByAppendingPathExtension:extension]];*/
284 } else {
285 // XXX: this code isn't really complete
286
287 [scaled addObject:file];
288
289 if ([base hasSuffix:[NSString stringWithFormat:@"~%@", idiom]])
290 [scaled addObject:[[base substringWithRange:NSMakeRange(0, [base length] - 1 - [idiom length])] stringByAppendingPathExtension:extension]];
291 }
292 }
293
294 return scaled;
295 }
296
297 static NSString *$getTheme$(NSArray *files, NSArray *themes = Themes_) {
298 // XXX: this is not reasonable; OMG
299 id key(files);
300
301 @synchronized (Themed_) {
302 if (NSString *path = [Themed_ objectForKey:key])
303 return reinterpret_cast<id>(path) == [NSNull null] ? nil : path;
304 }
305
306 if (Debug_)
307 NSLog(@"WB:Debug: %@", [files description]);
308
309 NSString *path;
310
311 for (NSString *theme in Themes_)
312 for (NSString *file in files) {
313 path = [NSString stringWithFormat:@"%@/%@", theme, file];
314 if ([Manager_ fileExistsAtPath:path]) {
315 if ([[Manager_ destinationOfSymbolicLinkAtPath:path error:NULL] isEqualToString:@"/"])
316 path = nil;
317 goto set;
318 }
319 }
320
321 path = nil;
322 set:
323
324 @synchronized (Themed_) {
325 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:key];
326 }
327
328 return path;
329 }
330 // }}}
331 // $pathForFile$inBundle$() {{{
332 static NSString *$pathForFile$inBundle$(NSString *file, NSString *identifier, NSString *folder, bool ui, bool use) {
333 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
334
335 if (identifier != nil)
336 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
337 if (folder != nil) {
338 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
339 NSString *base([folder stringByDeletingPathExtension]);
340 if ([base hasSuffix:@"~iphone"])
341 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 7)], [folder pathExtension], file]];
342 if ([base hasSuffix:@"~ipad"])
343 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 5)], [folder pathExtension], file]];
344 }
345 if (ui)
346 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
347
348 #define remapResourceName(oldname, newname) \
349 else if ([file isEqualToString:(oldname)]) \
350 [names addObject:[NSString stringWithFormat:@"%@.png", newname]]; \
351
352 bool summer(SpringBoard_ && SummerBoard_);
353
354 if (identifier == nil);
355 else if ([identifier isEqualToString:@"com.apple.chatkit"])
356 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.MobileSMS/%@", file]];
357 else if ([identifier isEqualToString:@"com.apple.calculator"])
358 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
359 else if ([identifier isEqualToString:@"com.apple.Maps"] && [file isEqualToString:@"Icon-57@2x.png"])
360 [names addObject:[NSString stringWithFormat:@"Bundles/com.apple.Maps/icon.png"]];
361 else if (!summer);
362 remapResourceName(@"FSO_BG.png", @"StatusBar")
363 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
364 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
365
366 [names addObject:[NSString stringWithFormat:@"Fallback/%@", file]];
367
368 if (NSString *path = $getTheme$($useScale$(names, use)))
369 return path;
370
371 return nil;
372 }
373
374 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool ui, bool use) {
375 return $pathForFile$inBundle$(file, [bundle bundleIdentifier], [[bundle bundlePath] lastPathComponent], ui, use);
376 }
377 // }}}
378
379 static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
380 NSString *identifier = [self bundleIdentifier];
381 NSString *path = [self path];
382 NSString *folder = [path lastPathComponent];
383 NSString *dname = [self displayName];
384 NSString *didentifier = [self displayIdentifier];
385
386 if (Debug_)
387 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
388
389 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
390
391 /* XXX: I might need to keep this for backwards compatibility
392 if (identifier != nil)
393 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
394 if (folder != nil)
395 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
396
397 #define testForIcon(Name) \
398 if (NSString *name = Name) \
399 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
400
401 if (![didentifier isEqualToString:identifier])
402 testForIcon(didentifier);
403
404 testForIcon(identifier);
405 testForIcon(dname);
406
407 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
408 testForIcon(@"SMS");
409
410 if (didentifier != nil) {
411 testForIcon([English_ objectForKey:didentifier]);
412
413 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
414 if ([parts count] != 1)
415 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
416 testForIcon([english objectForKey:[parts lastObject]]);
417 }
418
419 if (NSString *path = $getTheme$(names))
420 return path;
421
422 return nil;
423 }
424
425 // -[NSBundle wb$bundleWithFile] {{{
426 @interface NSBundle (WinterBoard)
427 + (NSBundle *) wb$bundleWithFile:(NSString *)path;
428 @end
429
430 @implementation NSBundle (WinterBoard)
431
432 + (NSBundle *) wb$bundleWithFile:(NSString *)path {
433 path = [path stringByDeletingLastPathComponent];
434 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
435 return nil;
436
437 NSBundle *bundle([Bundles_ objectForKey:path]);
438 if (reinterpret_cast<id>(bundle) == [NSNull null])
439 return nil;
440 else if (bundle == nil) {
441 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
442 bundle = [NSBundle bundleWithPath:path];
443 if (bundle == nil)
444 bundle = [NSBundle wb$bundleWithFile:path];
445 if (Debug_)
446 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
447 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
448 }
449
450 return bundle;
451 }
452
453 @end
454 // }}}
455 // -[NSString wb$themedPath] {{{
456 @interface NSString (WinterBoard)
457 - (NSString *) wb$themedPath;
458 @end
459
460 @implementation NSString (WinterBoard)
461
462 - (NSString *) wb$themedPath {
463 if ([self hasPrefix:@"/Library/Themes/"])
464 return self;
465
466 if (Debug_)
467 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
468
469 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
470 NSString *file([self stringByResolvingSymlinksInPath]);
471 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
472 if ([file hasPrefix:prefix]) {
473 NSUInteger length([prefix length]);
474 if (length != [file length])
475 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false, false))
476 return path;
477 }
478 }
479
480 return self;
481 }
482
483 @end
484 // }}}
485
486 void WBLogRect(const char *tag, struct CGRect rect) {
487 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
488 }
489
490 void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
491 CGRect frame([view frame]);
492 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]);
493 index = 0;
494 for (UIView *child in [view subviews])
495 WBLogHierarchy(child, index++, indent + 1);
496 }
497
498 UIImage *$cacheForImage$(UIImage *image) {
499 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
500 CGRect rect = {CGPointMake(1, 1), [image size]};
501 CGSize size = {rect.size.width + 2, rect.size.height + 2};
502
503 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
504 CGColorSpaceRelease(space);
505
506 CGContextDrawImage(context, rect, [image CGImage]);
507 CGImageRef ref(CGBitmapContextCreateImage(context));
508 CGContextRelease(context);
509
510 UIImage *cache([UIImage imageWithCGImage:ref]);
511 CGImageRelease(ref);
512
513 return cache;
514 }
515
516 /*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
517 //if ([name isEqualToString:@"icons"]) return nil;
518 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
519 }*/
520
521 MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
522 NSString *key([icon displayIdentifier]);
523
524 if (UIImage *image = [icon icon]) {
525 CGSize size = [image size];
526 if (size.width != 59 || size.height != 60) {
527 UIImage *cache($cacheForImage$(image));
528 [Cache_ setObject:cache forKey:key];
529 return;
530 }
531 }
532
533 _SBIconModel$cacheImageForIcon$(self, sel, icon);
534 }
535
536 MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
537 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
538 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
539
540 NSString *key([icon displayIdentifier]);
541
542 if (UIImage *image = [icon icon]) {
543 CGSize size = [image size];
544 if (size.width != 59 || size.height != 60) {
545 UIImage *cache($cacheForImage$(image));
546 [Cache_ setObject:cache forKey:key];
547 return;
548 }
549 }
550 }
551
552 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
553 NSString *key([icon displayIdentifier]);
554 if (UIImage *image = [Cache_ objectForKey:key])
555 return image;
556 else
557 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
558 }
559
560 MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
561 if (small)
562 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
563 NSString *key([icon displayIdentifier]);
564 if (UIImage *image = [Cache_ objectForKey:key])
565 return image;
566 else
567 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
568 }
569
570 MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
571 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
572 [self setBackgroundColor:[UIColor clearColor]];
573 for (UIView *child in [self subviews])
574 [child setBackgroundColor:[UIColor clearColor]];
575 } return self;
576 }
577
578 MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
579 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
580 [self setBackgroundColor:[UIColor clearColor]];
581 } return self;
582 }
583
584 MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
585 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
586 float inset([self edgeInset]);
587 [[UIColor clearColor] set];
588 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
589 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
590 }
591
592 MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
593 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
594 if (NSString *path = $pathForIcon$([self application]))
595 return [UIImage imageWithContentsOfFile:path];
596 return _SBApplicationIcon$icon(self, sel);
597 }
598
599 MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
600 if (type == 2)
601 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
602 if (IsWild_ && false) // XXX: delete this code, it should not be supported
603 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
604 return [UIImage imageWithContentsOfFile:path72];
605 if (NSString *path = $pathForIcon$([self application]))
606 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
607 CGFloat width;
608 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
609 width = [$SBIcon defaultIconImageSize].width;
610 else
611 width = 59;
612 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
613 }
614 }
615 return _SBApplicationIcon$generateIconImage$(self, sel, type);
616 }
617
618 MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
619 if (Debug_)
620 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
621 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
622 return [UIImage imageWithContentsOfFile:path];
623 return _SBWidgetApplicationIcon$icon(self, sel);
624 }
625
626 MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
627 if (Debug_)
628 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
629 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
630 return [UIImage imageWithContentsOfFile:path];
631 return _SBBookmarkIcon$icon(self, sel);
632 }
633
634 MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
635 if (NSString *path = $pathForIcon$(self))
636 return path;
637 return _SBApplication$pathForIcon(self, sel);
638 }
639
640 static UIImage *CachedImageAtPath(NSString *path) {
641 path = [path stringByResolvingSymlinksInPath];
642 UIImage *image = [Images_ objectForKey:path];
643 if (image != nil)
644 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
645 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
646 if (image != nil)
647 image = [image autorelease];
648 [Images_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
649 return image;
650 }
651
652 MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
653 NSBundle *bundle = [NSBundle mainBundle];
654 if (Debug_)
655 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
656 if (NSString *path = $pathForFile$inBundle$(name, bundle, false, false))
657 return CachedImageAtPath(path);
658 return __UIApplicationImageWithName(name);
659 }
660
661 #define WBDelegate(delegate) \
662 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
663 if (Engineer_) \
664 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
665 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
666 return sig; \
667 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
668 return nil; \
669 } \
670 \
671 - (void) forwardInvocation:(NSInvocation*)inv { \
672 SEL sel = [inv selector]; \
673 if ([delegate respondsToSelector:sel]) \
674 [inv invokeWithTarget:delegate]; \
675 else \
676 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
677 }
678
679 // %hook -[NSBundle pathForResource:ofType:] {{{
680 MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, resource, NSString *, type) {
681 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
682 if ([file isEqualToString:@"Info.plist"])
683 return MSOldCall(resource, type);
684 if (Debug_)
685 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
686 if (NSString *path = $pathForFile$inBundle$(file, self, false, false))
687 return path;
688 return MSOldCall(resource, type);
689 }
690 // }}}
691
692 static void $drawLabel$(NSString *label, CGRect rect, NSString *style, NSString *custom) {
693 bool ellipsis(false);
694 CGFloat max = rect.size.width - 11, width;
695 width:
696 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
697
698 if (width > max) {
699 size_t length([label length]);
700 CGFloat spacing((width - max) / (length - 1));
701
702 if (spacing > 1.25) {
703 ellipsis = true;
704 label = [label substringToIndex:(length - 1)];
705 goto width;
706 }
707
708 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
709 }
710
711 if (ellipsis)
712 label = [label stringByAppendingString:@"..."];
713
714 if (custom != nil)
715 style = [style stringByAppendingString:custom];
716
717 CGSize size = [label sizeWithStyle:style forWidth:rect.size.width];
718 [label drawAtPoint:CGPointMake((rect.size.width - size.width) / 2 + rect.origin.x, rect.origin.y) withStyle:style];
719 }
720
721 static struct WBStringDrawingState {
722 WBStringDrawingState *next_;
723 unsigned count_;
724 NSString *base_;
725 NSString *info_;
726 } *stringDrawingState_;
727
728 extern "C" CGColorSpaceRef CGContextGetFillColorSpace(CGContextRef);
729 extern "C" void CGContextGetFillColor(CGContextRef, CGFloat[]);
730
731 static NSString *WBColorMarkup(size_t number, const CGFloat *components) {
732 CGFloat r, g, b, a;
733
734 switch (number) {
735 case 1:
736 r = components[0];
737 g = components[0];
738 b = components[0];
739 a = components[1];
740 break;
741
742 case 3:
743 r = components[0];
744 g = components[1];
745 b = components[2];
746 a = components[3];
747 break;
748
749 default:
750 return @"";
751 }
752
753 return [NSString stringWithFormat:@"color: rgba(%g, %g, %g, %g)", r * 255, g * 255, b * 255, a];
754 }
755
756 static NSString *WBColorMarkup() {
757 CGContextRef context(UIGraphicsGetCurrentContext());
758 //NSLog(@"XXX:1:%p", context);
759 if (context == NULL)
760 return @"";
761
762 CGColorSpaceRef space(CGContextGetFillColorSpace(context));
763 //NSLog(@"XXX:2:%p", space);
764 if (space == NULL)
765 return @"";
766
767 size_t number(CGColorSpaceGetNumberOfComponents(space));
768 //NSLog(@"XXX:3:%u", number);
769 if (number == 0)
770 return @"";
771
772 CGFloat components[number + 1];
773 CGContextGetFillColor(context, components);
774 return WBColorMarkup(number, components);
775 }
776
777 static NSString *WBColorMarkup(UIColor *uicolor) {
778 if (uicolor == nil)
779 return @"";
780 CGColorRef cgcolor([uicolor CGColor]);
781 if (cgcolor == NULL)
782 return @"";
783
784 CGColorSpaceRef space(CGColorGetColorSpace(cgcolor));
785 //NSLog(@"XXX:2:%p", space);
786 if (space == NULL)
787 return @"";
788
789 size_t number(CGColorGetNumberOfComponents(cgcolor));
790 //NSLog(@"XXX:3:%u", number);
791 if (number == 0)
792 return @"";
793
794 const CGFloat *components(CGColorGetComponents(cgcolor));
795 return WBColorMarkup(number, components);
796 }
797
798 extern "C" NSString *NSStringFromCGPoint(CGPoint rect);
799
800 MSInstanceMessage6(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode,letterSpacing,includeEmoji, CGPoint, point, CGFloat, width, UIFont *, font, UILineBreakMode, mode, CGFloat, spacing, BOOL, emoji) {
801 //NSLog(@"XXX: @\"%@\" %@ %g \"%@\" %u %g %u", self, NSStringFromCGPoint(point), width, font, mode, spacing, emoji);
802
803 WBStringDrawingState *state(stringDrawingState_);
804 if (state == NULL)
805 return MSOldCall(point, width, font, mode, spacing, emoji);
806
807 if (state->count_ != 0 && --state->count_ == 0)
808 stringDrawingState_ = state->next_;
809 if (state->info_ == nil)
810 return MSOldCall(point, width, font, mode, spacing, emoji);
811
812 NSString *info([Info_ objectForKey:state->info_]);
813 if (info == nil)
814 return MSOldCall(point, width, font, mode, spacing, emoji);
815
816 NSString *base(state->base_ ?: @"");
817 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
818 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
819 return CGSizeZero;
820 }
821
822 extern "C" NSString *NSStringFromCGRect(CGRect rect);
823
824 MSInstanceMessageHook7(CGSize, NSString, _drawInRect,withFont,lineBreakMode,alignment,lineSpacing,includeEmoji,truncationRect, CGRect, rect, UIFont *, font, UILineBreakMode, mode, UITextAlignment, alignment, float, spacing, BOOL, emoji, CGRect, truncation) {
825 //NSLog(@"XXX: @\"%@\" %@ \"%@\" %u %u %g %u %@", self, NSStringFromCGRect(rect), font, mode, alignment, spacing, emoji, NSStringFromCGRect(truncation));
826
827 WBStringDrawingState *state(stringDrawingState_);
828 if (state == NULL)
829 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
830
831 if (state->count_ != 0 && --state->count_ == 0)
832 stringDrawingState_ = state->next_;
833 if (state->info_ == nil)
834 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
835
836 NSString *info([Info_ objectForKey:state->info_]);
837 if (info == nil)
838 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
839
840 NSString *textAlign;
841 switch (alignment) {
842 default:
843 case UITextAlignmentLeft:
844 textAlign = @"left";
845 break;
846 case UITextAlignmentCenter:
847 textAlign = @"center";
848 break;
849 case UITextAlignmentRight:
850 textAlign = @"right";
851 break;
852 }
853
854 NSString *base(state->base_ ?: @"");
855 NSString *extra([NSString stringWithFormat:@"text-align: %@", textAlign]);
856
857 if (true)
858 $drawLabel$(self, rect, [NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], WBColorMarkup(), base], info);
859 else
860 [self drawInRect:rect withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
861
862 return CGSizeZero;
863 }
864
865 MSInstanceMessage2(void, NSString, drawInRect,withAttributes, CGRect, rect, NSDictionary *, attributes) {
866 //NSLog(@"XXX: *\"%@\" %@", self, attributes);
867
868 WBStringDrawingState *state(stringDrawingState_);
869 if (state == NULL)
870 return MSOldCall(rect, attributes);
871
872 if (state->count_ != 0 && --state->count_ == 0)
873 stringDrawingState_ = state->next_;
874 if (state->info_ == nil)
875 return MSOldCall(rect, attributes);
876
877 NSString *info([Info_ objectForKey:state->info_]);
878 if (info == nil)
879 return MSOldCall(rect, attributes);
880
881 NSString *base(state->base_ ?: @"");
882
883 UIFont *font([attributes objectForKey:@"NSFont"]);
884 UIColor *color([attributes objectForKey:@"NSColor"]);
885
886 [self drawInRect:rect withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(color), base, info]];
887 }
888
889 extern "C" NSString *NSStringFromCGSize(CGSize size);
890
891 MSInstanceMessage4(CGRect, NSString, boundingRectWithSize,options,attributes,context, CGSize, size, NSInteger, options, NSDictionary *, attributes, id, context) {
892 //NSLog(@"XXX: $\"%@\" %@ 0x%x %@ %@", self, NSStringFromCGSize(size), unsigned(options), attributes, context);
893
894 WBStringDrawingState *state(stringDrawingState_);
895 if (state == NULL)
896 return MSOldCall(size, options, attributes, context);
897
898 if (state->count_ != 0 && --state->count_ == 0)
899 stringDrawingState_ = state->next_;
900 if (state->info_ == nil)
901 return MSOldCall(size, options, attributes, context);
902
903 NSString *info([Info_ objectForKey:state->info_]);
904 if (info == nil)
905 return MSOldCall(size, options, attributes, context);
906
907 NSString *base(state->base_ ?: @"");
908
909 UIFont *font([attributes objectForKey:@"NSFont"]);
910 UIColor *color([attributes objectForKey:@"NSColor"]);
911
912 return (CGRect) {{0, 0}, [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(color), base, info] forWidth:size.width]};
913 }
914
915 MSInstanceMessage4(CGSize, NSString, sizeWithFont,forWidth,lineBreakMode,letterSpacing, UIFont *, font, CGFloat, width, UILineBreakMode, mode, CGFloat, spacing) {
916 //NSLog(@"XXX: #\"%@\" \"%@\" %g %u %g", self, font, width, mode, spacing);
917
918 WBStringDrawingState *state(stringDrawingState_);
919 if (state == NULL)
920 return MSOldCall(font, width, mode, spacing);
921
922 if (state->count_ != 0 && --state->count_ == 0)
923 stringDrawingState_ = state->next_;
924 if (state->info_ == nil)
925 return MSOldCall(font, width, mode, spacing);
926
927 NSString *info([Info_ objectForKey:state->info_]);
928 if (info == nil)
929 return MSOldCall(font, width, mode, spacing);
930
931 NSString *base(state->base_ ?: @"");
932 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
933 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info] forWidth:width];
934 }
935
936 MSInstanceMessage1(CGSize, NSString, sizeWithFont, UIFont *, font) {
937 //NSLog(@"XXX: ?\"%@\"", self);
938
939 WBStringDrawingState *state(stringDrawingState_);
940 if (state == NULL)
941 return MSOldCall(font);
942
943 if (state->count_ != 0 && --state->count_ == 0)
944 stringDrawingState_ = state->next_;
945 if (state->info_ == nil)
946 return MSOldCall(font);
947
948 NSString *info([Info_ objectForKey:state->info_]);
949 if (info == nil)
950 return MSOldCall(font);
951
952 NSString *base(state->base_ ?: @"");
953 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), base, info] forWidth:65535];
954 }
955
956 MSClassMessageHook2(id, SBIconBadgeView, checkoutAccessoryImagesForIcon,location, id, icon, int, location) {
957 WBStringDrawingState badgeState = {NULL, 0, @""
958 , @"BadgeStyle"};
959
960 stringDrawingState_ = &badgeState;
961
962 id images(MSOldCall(icon, location));
963
964 stringDrawingState_ = NULL;
965 return images;
966 }
967
968 MSClassMessageHook2(UIImage *, SBIconAccessoryImage, checkoutAccessoryImageForIcon,location, id, icon, int, location) {
969 if ([self _imageClassForIcon:icon location:location] != $SBIconBadgeImage)
970 return MSOldCall(icon, location);
971
972 WBStringDrawingState badgeState = {NULL, 0, @""
973 , @"BadgeStyle"};
974
975 stringDrawingState_ = &badgeState;
976
977 UIImage *image(MSOldCall(icon, location));
978
979 stringDrawingState_ = NULL;
980 return image;
981 }
982
983 MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
984 WBStringDrawingState badgeState = {NULL, 0, @""
985 , @"BadgeStyle"};
986
987 stringDrawingState_ = &badgeState;
988
989 UIImage *image(MSOldCall(text));
990
991 stringDrawingState_ = NULL;
992 return image;
993 }
994
995 MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
996 WBStringDrawingState dayState = {NULL, 2, @""
997 // XXX: this is only correct on an iPod dock
998 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
999 , @"CalendarIconDayStyle"};
1000
1001 WBStringDrawingState skipState = {&dayState,
1002 unsigned(kCFCoreFoundationVersionNumber > 800 ? 16 : 7)
1003 , nil, nil};
1004
1005 WBStringDrawingState dateState = {&skipState, 2, @""
1006 , @"CalendarIconDateStyle"};
1007
1008 stringDrawingState_ = &dateState;
1009
1010 UIImage *image(MSOldCall(type));
1011
1012 stringDrawingState_ = NULL;
1013 return image;
1014 }
1015
1016 MSInstanceMessageHook1(UIImage *, UIStatusBarTimeItemView, contentsImageForStyle, int, style) {
1017 WBStringDrawingState timeState = {NULL, 0, @""
1018 , @"TimeStyle"};
1019
1020 stringDrawingState_ = &timeState;
1021
1022 UIImage *image(MSOldCall(style));
1023
1024 stringDrawingState_ = NULL;
1025 return image;
1026 }
1027
1028 MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
1029 NSBundle *bundle([NSBundle mainBundle]);
1030
1031 CFLocaleRef locale(CFLocaleCopyCurrent());
1032 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
1033 CFRelease(locale);
1034
1035 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
1036
1037 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
1038 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
1039 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
1040 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
1041
1042 CFRelease(now);
1043
1044 CFRelease(formatter);
1045
1046 NSString *datestyle([@""
1047 "font-family: Helvetica; "
1048 "font-weight: bold; "
1049 "color: #333333; "
1050 "alpha: 1.0; "
1051 "" stringByAppendingString:(IsWild_
1052 ? @"font-size: 54px; "
1053 : @"font-size: 39px; "
1054 )]);
1055
1056 NSString *daystyle([@""
1057 "font-family: Helvetica; "
1058 "font-weight: bold; "
1059 "color: white; "
1060 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
1061 "" stringByAppendingString:(IsWild_
1062 ? @"font-size: 11px; "
1063 : @"font-size: 9px; "
1064 )]);
1065
1066 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
1067 datestyle = [datestyle stringByAppendingString:style];
1068 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
1069 daystyle = [daystyle stringByAppendingString:style];
1070
1071 CGFloat width([self bounds].size.width);
1072 float leeway(10);
1073 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
1074 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
1075
1076 unsigned base0(IsWild_ ? 89 : 70);
1077 if ($GSFontGetUseLegacyFontMetrics())
1078 base0 = base0 + 1;
1079 unsigned base1(IsWild_ ? 18 : 16);
1080
1081 if (Four_) {
1082 ++base0;
1083 ++base1;
1084 }
1085
1086 [(NSString *)date drawAtPoint:CGPointMake(
1087 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
1088 ) withStyle:datestyle];
1089
1090 [(NSString *)day drawAtPoint:CGPointMake(
1091 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
1092 ) withStyle:daystyle];
1093
1094 CFRelease(date);
1095 CFRelease(day);
1096 }
1097
1098 // %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
1099 void $setBarStyle$_(NSString *name, int &style) {
1100 if (Debug_)
1101 NSLog(@"WB:Debug:%@Style:%d", name, style);
1102 NSNumber *number = nil;
1103 if (number == nil)
1104 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
1105 if (number == nil)
1106 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
1107 if (number != nil) {
1108 style = [number intValue];
1109 if (Debug_)
1110 NSLog(@"WB:Debug:%@Style=%d", name, style);
1111 }
1112 }
1113
1114 MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
1115 $setBarStyle$_(@"Toolbar", style);
1116 return MSOldCall(style);
1117 }
1118
1119 MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
1120 $setBarStyle$_(@"NavigationBar", style);
1121 return MSOldCall(style);
1122 }
1123 // }}}
1124
1125 MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
1126 [[self superview] setBackgroundColor:[UIColor clearColor]];
1127 _SBButtonBar$didMoveToSuperview(self, sel);
1128 }
1129
1130 MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
1131 [[self superview] setBackgroundColor:[UIColor clearColor]];
1132 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
1133 }
1134
1135 static NSArray *Wallpapers_;
1136 static bool Papered_;
1137 static bool Docked_;
1138 static bool SMSBackgrounded_;
1139 static NSString *WallpaperFile_;
1140 static UIImageView *WallpaperImage_;
1141 static UIWebDocumentView *WallpaperPage_;
1142 static NSURL *WallpaperURL_;
1143
1144 #define _release(object) \
1145 do if (object != nil) { \
1146 [object release]; \
1147 object = nil; \
1148 } while (false)
1149
1150 static UIImage *$getImage$(NSString *path) {
1151 UIImage *image([UIImage imageWithContentsOfFile:path]);
1152
1153 unsigned scale($getScale$(path));
1154 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
1155 [image setScale:scale];
1156
1157 return image;
1158 }
1159
1160 template <typename Original_, typename Modified_>
1161 _finline UIImage *WBCacheImage(const Original_ &original, const Modified_ &modified, NSString *key) {
1162 UIImage *image([Images_ objectForKey:key]);
1163 if (image != nil)
1164 return reinterpret_cast<id>(image) == [NSNull null] ? original() : image;
1165 if (NSString *path = modified())
1166 image = $getImage$(path);
1167 [Images_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1168 return image == nil ? original() : image;
1169 }
1170
1171 static UIImage *$getDefaultDesktopImage$() {
1172 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
1173 return $getImage$(path);
1174 return nil;
1175 }
1176
1177 MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
1178 return $getDefaultDesktopImage$() ?: MSOldCall();
1179 }
1180
1181 MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
1182 return $getDefaultDesktopImage$() ?: MSOldCall();
1183 }
1184
1185 MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
1186 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
1187 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
1188 if (UIImage *image = $getDefaultDesktopImage$()) {
1189 [self setImage:image];
1190 return;
1191 }
1192
1193 break;
1194 }
1195
1196 MSOldCall();
1197 }
1198
1199 // %hook -[SBUIController init] {{{
1200 MSInstanceMessageHook0(id, SBUIController, init) {
1201 self = MSOldCall();
1202 if (self == nil)
1203 return nil;
1204
1205 NSString *paper($getTheme$(Wallpapers_));
1206 if (paper != nil)
1207 paper = [paper stringByDeletingLastPathComponent];
1208
1209 {
1210 size_t size;
1211 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
1212 char *machine = new char[size];
1213
1214 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
1215 perror("sysctlbyname(\"hw.machine\", ?)");
1216 delete [] machine;
1217 machine = NULL;
1218 }
1219
1220 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
1221 }
1222
1223 if (Debug_)
1224 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
1225
1226 if (paper != nil) {
1227 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
1228 if (&_wallpaperView != NULL) {
1229 [_wallpaperView removeFromSuperview];
1230 [_wallpaperView release];
1231 _wallpaperView = nil;
1232 }
1233 }
1234
1235 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
1236 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
1237
1238 UIView **player;
1239 if (&_contentLayer != NULL)
1240 player = &_contentLayer;
1241 else if (&_contentView != NULL)
1242 player = &_contentView;
1243 else
1244 player = NULL;
1245 UIView *layer(player == NULL ? nil : *player);
1246
1247 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
1248 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
1249 [window setContentView:content];
1250
1251 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
1252 [window setBackgroundColor:[_window backgroundColor]];
1253 [_window setBackgroundColor:[UIColor clearColor]];
1254
1255 [window setLevel:-1000];
1256 [window setHidden:NO];
1257
1258 /*if (player != NULL)
1259 *player = content;*/
1260
1261 [content setBackgroundColor:[layer backgroundColor]];
1262 [layer setBackgroundColor:[UIColor clearColor]];
1263
1264 UIView *indirect;
1265 if (!SummerBoard_ || !IsWild_)
1266 indirect = content;
1267 else {
1268 CGRect bounds([content bounds]);
1269 bounds.origin.y = -30;
1270 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
1271 [content addSubview:indirect];
1272 [indirect zoomToScale:2.4];
1273 }
1274
1275 _release(WallpaperFile_);
1276 _release(WallpaperImage_);
1277 _release(WallpaperPage_);
1278 _release(WallpaperURL_);
1279
1280 if (paper != nil) {
1281 NSArray *themes([NSArray arrayWithObject:paper]);
1282
1283 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
1284 #if UseAVController
1285 NSError *error;
1286
1287 static AVController *controller_(nil);
1288 if (controller_ == nil) {
1289 AVQueue *queue([AVQueue avQueue]);
1290 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1291 }
1292
1293 AVQueue *queue([controller_ queue]);
1294
1295 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
1296 [controller_ setLayer:[video _layer]];
1297
1298 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
1299 [queue appendItem:item error:&error];
1300
1301 [controller_ play:&error];
1302 #elif UseMPMoviePlayerController
1303 NSURL *url([NSURL fileURLWithPath:path]);
1304 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
1305 controller.movieControlMode = MPMovieControlModeHidden;
1306 [controller play];
1307 #else
1308 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
1309 [video setMovieWithPath:path];
1310 [video setRepeatMode:1];
1311 [video setRepeatGap:-1];
1312 [video playFromBeginning];;
1313 #endif
1314
1315 [indirect addSubview:video];
1316 }
1317
1318 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
1319 if (UIImage *image = $getImage$(path)) {
1320 WallpaperFile_ = [path retain];
1321 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1322 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1323 [WallpaperImage_ setAlpha:[number floatValue]];
1324 [indirect addSubview:WallpaperImage_];
1325 }
1326 }
1327
1328 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1329 CGRect bounds = [indirect bounds];
1330
1331 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1332 [view setAutoresizes:true];
1333
1334 WallpaperPage_ = [view retain];
1335 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1336
1337 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1338
1339 [view setBackgroundColor:[UIColor clearColor]];
1340 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1341 [view setDrawsBackground:NO];
1342 [[view webView] setDrawsBackground:NO];
1343
1344 [indirect addSubview:view];
1345 }
1346 }
1347
1348 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1349 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
1350 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1351 if ([Manager_ fileExistsAtPath:html]) {
1352 CGRect bounds = [indirect bounds];
1353
1354 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1355 [view setAutoresizes:true];
1356
1357 NSURL *url = [NSURL fileURLWithPath:html];
1358 [view loadRequest:[NSURLRequest requestWithURL:url]];
1359
1360 [view setBackgroundColor:[UIColor clearColor]];
1361 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1362 [view setDrawsBackground:NO];
1363 [[view webView] setDrawsBackground:NO];
1364
1365 [indirect addSubview:view];
1366 }
1367 }
1368
1369 return self;
1370 }
1371 // }}}
1372
1373 MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
1374 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
1375 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1376
1377 if (path != nil && _backgroundView != nil)
1378 path = nil;
1379
1380 _SBAwayView$updateDesktopImage$(self, sel, image);
1381
1382 if (path != nil) {
1383 CGRect bounds = [self bounds];
1384
1385 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1386 [view setAutoresizes:true];
1387
1388 if (WallpaperPage_ != nil)
1389 [WallpaperPage_ release];
1390 WallpaperPage_ = [view retain];
1391
1392 if (WallpaperURL_ != nil)
1393 [WallpaperURL_ release];
1394 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1395
1396 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1397
1398 [[view webView] setDrawsBackground:false];
1399 [view setBackgroundColor:[UIColor clearColor]];
1400
1401 [self insertSubview:view aboveSubview:_backgroundView];
1402
1403 if ($objc_setAssociatedObject != NULL)
1404 $objc_setAssociatedObject(self, @selector(wb$widgetView), view, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1405 }
1406 }
1407
1408 MSHook(void, SBAwayView$_addSubview$positioned$relativeTo$, SBAwayView *self, SEL sel, UIView *view, int positioned, UIView *relative) {
1409 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1410 UIView *&_chargingView(MSHookIvar<UIView *>(self, "_chargingView"));
1411 if (&_chargingView != NULL)
1412 if (positioned == -2 && (relative == _backgroundView && _chargingView == nil || relative == _chargingView))
1413 if ($objc_getAssociatedObject != NULL)
1414 if (UIView *widget = $objc_getAssociatedObject(self, @selector(wb$widgetView)))
1415 relative = widget;
1416 return _SBAwayView$_addSubview$positioned$relativeTo$(self, sel, view, positioned, relative);
1417 }
1418
1419 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
1420 extern "C" CGColorRef CGGStateGetFillColor(void *);
1421 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
1422 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
1423
1424 /* WBTimeLabel {{{ */
1425 @interface WBTimeLabel : NSProxy {
1426 NSString *time_;
1427 _transient SBStatusBarTimeView *view_;
1428 }
1429
1430 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
1431
1432 @end
1433
1434 @implementation WBTimeLabel
1435
1436 - (void) dealloc {
1437 [time_ release];
1438 [super dealloc];
1439 }
1440
1441 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1442 time_ = [time retain];
1443 view_ = view;
1444 return self;
1445 }
1446
1447 - (NSString *) description {
1448 return time_;
1449 }
1450
1451 WBDelegate(time_)
1452
1453 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1454 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
1455 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
1456
1457 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1458 "font-family: Helvetica; "
1459 "font-weight: bold; "
1460 "font-size: 14px; "
1461 "color: %@; "
1462 "%@", _mode ? @"white" : @"black", custom]];
1463
1464 return CGSizeZero;
1465 }
1466
1467 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1468 }
1469
1470 @end
1471 /* }}} */
1472 /* WBBadgeLabel {{{ */
1473 @interface WBBadgeLabel : NSProxy {
1474 NSString *badge_;
1475 }
1476
1477 - (id) initWithBadge:(NSString *)badge;
1478 - (NSString *) description;
1479
1480 @end
1481
1482 @implementation WBBadgeLabel
1483
1484 - (void) dealloc {
1485 [badge_ release];
1486 [super dealloc];
1487 }
1488
1489 - (id) initWithBadge:(NSString *)badge {
1490 badge_ = [badge retain];
1491 return self;
1492 }
1493
1494 - (NSString *) description {
1495 return [badge_ description];
1496 }
1497
1498 WBDelegate(badge_)
1499
1500 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
1501 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1502 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1503 "font-family: Helvetica; "
1504 "font-weight: bold; "
1505 "font-size: 17px; "
1506 "color: white; "
1507 "%@", custom]];
1508
1509 return CGSizeZero;
1510 }
1511
1512 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1513 }
1514
1515 @end
1516 /* }}} */
1517
1518 // IconAlpha {{{
1519 MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, CGFloat, alpha) {
1520 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1521 alpha = [number floatValue];
1522 return MSOldCall(alpha);
1523 }
1524
1525 MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, CGFloat, alpha) {
1526 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1527 alpha = [number floatValue];
1528 return MSOldCall(alpha);
1529 }
1530
1531 MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1532 if ((self = MSOldCall()) != nil) {
1533 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1534 // XXX: note: this is overridden above, which is silly
1535 float alpha([number floatValue]);
1536 if ([self respondsToSelector:@selector(setIconImageAlpha:)])
1537 [self setIconImageAlpha:alpha];
1538 if ([self respondsToSelector:@selector(setIconLabelAlpha:)])
1539 [self setIconLabelAlpha:alpha];
1540 if ([self respondsToSelector:@selector(setAlpha:)])
1541 [self setAlpha:alpha];
1542 }
1543 } return self;
1544 }
1545
1546 MSInstanceMessageHook1(void, SBIcon, setAlpha, CGFloat, alpha) {
1547 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1548 alpha = [number floatValue];
1549 return MSOldCall(alpha);
1550 }
1551 // }}}
1552
1553 MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1554 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
1555 id &_badge(MSHookIvar<id>(self, "_badge"));
1556 if (_badge != nil)
1557 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1558 _badge = label;
1559 } return self;
1560 }
1561
1562 void SBStatusBarController$setStatusBarMode(int &mode) {
1563 if (Debug_)
1564 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
1565 if (mode < 100) // 104:hidden 105:glowing
1566 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1567 mode = [number intValue];
1568 }
1569
1570 /*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1571 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1572 SBStatusBarController$setStatusBarMode(mode);
1573 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1574 }*/
1575
1576 MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
1577 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
1578 SBStatusBarController$setStatusBarMode(mode);
1579 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1580 }
1581
1582 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) {
1583 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
1584 SBStatusBarController$setStatusBarMode(mode);
1585 //NSLog(@"mode=%u", mode);
1586 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1587 }
1588
1589 /*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
1590 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1591 mode = [number intValue];
1592 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
1593 }*/
1594
1595 MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1596 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
1597 if (Debug_)
1598 NSLog(@"operatorNameStyle= %@", style);
1599 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1600 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1601 return style;
1602 }
1603
1604 MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
1605 if (Debug_)
1606 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
1607 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
1608 }
1609
1610 // XXX: replace this with [SBStatusBarTimeView tile]
1611 MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
1612 id &_time(MSHookIvar<id>(self, "_time"));
1613 if (_time != nil && [_time class] != [WBTimeLabel class])
1614 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
1615 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
1616 }
1617
1618 @interface UIView (WinterBoard)
1619 - (bool) wb$isWBImageView;
1620 - (void) wb$logHierarchy;
1621 - (void) wb$setBackgroundColor:(UIColor *)color;
1622 @end
1623
1624 @implementation UIView (WinterBoard)
1625
1626 - (bool) wb$isWBImageView {
1627 return false;
1628 }
1629
1630 - (void) wb$logHierarchy {
1631 WBLogHierarchy(self);
1632 }
1633
1634 - (void) wb$setBackgroundColor:(UIColor *)color {
1635 [self setBackgroundColor:color];
1636 for (UIView *child in [self subviews])
1637 [child wb$setBackgroundColor:color];
1638 }
1639
1640 @end
1641
1642 @interface WBImageView : UIImageView {
1643 }
1644
1645 - (bool) wb$isWBImageView;
1646 - (void) wb$updateFrame;
1647 @end
1648
1649 @implementation WBImageView
1650
1651 - (bool) wb$isWBImageView {
1652 return true;
1653 }
1654
1655 - (void) wb$updateFrame {
1656 CGRect frame([self frame]);
1657 frame.origin.y = 0;
1658
1659 for (UIView *view(self); ; ) {
1660 view = [view superview];
1661 if (view == nil)
1662 break;
1663 frame.origin.y -= [view frame].origin.y;
1664 }
1665
1666 [self setFrame:frame];
1667 }
1668
1669 @end
1670
1671 static void SBIconList$updateFrames$(SBIconList *self) {
1672 NSArray *subviews([self subviews]);
1673 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1674 if (view != nil && [view wb$isWBImageView])
1675 [view wb$updateFrame];
1676 }
1677
1678 MSHook(void, SBIconList$didMoveToSuperview, SBIconList *self, SEL sel) {
1679 SBIconList$updateFrames$(self);
1680 _SBIconList$didMoveToSuperview(self, sel);
1681 }
1682
1683 MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1684 SBIconList$updateFrames$(self);
1685 _SBIconList$setFrame$(self, sel, frame);
1686 }
1687
1688 static void $addPerPageView$(unsigned i, UIView *list) {
1689 NSString *path($getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]]));
1690 if (path == nil)
1691 return;
1692
1693 NSArray *subviews([list subviews]);
1694
1695 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1696 if (view == nil || ![view wb$isWBImageView]) {
1697 view = [[[WBImageView alloc] init] autorelease];
1698 [list insertSubview:view atIndex:0];
1699 }
1700
1701 UIImage *image([UIImage imageWithContentsOfFile:path]);
1702
1703 CGRect frame([view frame]);
1704 frame.size = [image size];
1705 [view setFrame:frame];
1706
1707 [view setImage:image];
1708 [view wb$updateFrame];
1709 }
1710
1711 static void $addPerPageViews$(NSArray *lists) {
1712 for (unsigned i(0), e([lists count]); i != e; ++i)
1713 $addPerPageView$(i, [lists objectAtIndex:i]);
1714 }
1715
1716 MSInstanceMessageHook0(void, SBIconController, updateNumberOfRootIconLists) {
1717 NSArray *&_rootIconLists(MSHookIvar<NSArray *>(self, "_rootIconLists"));
1718 $addPerPageViews$(_rootIconLists);
1719 return MSOldCall();
1720 }
1721
1722 MSInstanceMessageHook0(void, SBIconContentView, layoutSubviews) {
1723 MSOldCall();
1724
1725 if (SBIconController *controller = [$SBIconController sharedInstance]) {
1726 UIView *&_dockContainerView(MSHookIvar<UIView *>(controller, "_dockContainerView"));
1727 if (&_dockContainerView != NULL)
1728 [[_dockContainerView superview] bringSubviewToFront:_dockContainerView];
1729 }
1730 }
1731
1732 MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1733 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1734 $addPerPageViews$([_iconModel iconLists]);
1735 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
1736 }
1737
1738 MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1739 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
1740 if (self != nil)
1741 [self setClipsToBounds:NO];
1742 return self;
1743 }
1744
1745 MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
1746 static bool gssc(false);
1747 if (!gssc) {
1748 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1749 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1750 gssc = true;
1751
1752 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1753 [Info_ setObject:[NSNumber numberWithBool:(
1754 !Papered_ ||
1755 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1756 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1757 )] forKey:@"UndockedIconLabels"];
1758 }
1759
1760 id &_label(MSHookIvar<id>(self, "_label"));
1761 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
1762 docked = true;
1763
1764 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1765 [_label setInDock:docked];
1766
1767 _SBIconLabel$setInDock$(self, sel, docked);
1768 [self setNeedsDisplay];
1769 }
1770
1771 MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1772 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1773 }
1774
1775 MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1776 _SBDockIconListView$setFrame$(self, sel, frame);
1777 }
1778
1779 // %hook -[NSBundle localizedStringForKey:value:table:] {{{
1780 MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
1781 NSString *identifier = [self bundleIdentifier];
1782 NSLocale *locale = [NSLocale currentLocale];
1783 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
1784 if (Debug_)
1785 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1786 NSString *file = table == nil ? @"Localizable" : table;
1787 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1788 NSDictionary *strings;
1789 if ((strings = [Strings_ objectForKey:name]) != nil) {
1790 if (static_cast<id>(strings) != [NSNull null]) strings:
1791 if (NSString *value = [strings objectForKey:key])
1792 return value;
1793 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1794 language, file
1795 ], self, false, false)) {
1796 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1797 [Strings_ setObject:[strings autorelease] forKey:name];
1798 goto strings;
1799 } else goto null;
1800 } else null:
1801 [Strings_ setObject:[NSNull null] forKey:name];
1802 return MSOldCall(key, value, table);
1803 }
1804 // }}}
1805 // %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1806 MSClassHook(WebCoreFrameBridge)
1807
1808 MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
1809 if (node == nil)
1810 return CGSizeZero;
1811 void **core(reinterpret_cast<void **>([node _node]));
1812 if (core == NULL || core[6] == NULL)
1813 return CGSizeZero;
1814 return MSOldCall(node, width);
1815 }
1816 // }}}
1817
1818 MSInstanceMessage1(void, SBIconLabel, drawRect, CGRect, rect) {
1819 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1820
1821 int docked;
1822 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1823 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
1824
1825 NSString *label(MSHookIvar<NSString *>(self, "_label"));
1826
1827 NSString *style = [NSString stringWithFormat:@""
1828 "font-family: Helvetica; "
1829 "font-weight: bold; "
1830 "color: %@; %@"
1831 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
1832 ? @"font-size: 12px; "
1833 : @"font-size: 11px; "
1834 )];
1835
1836 if (IsWild_)
1837 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1838 else if (docked)
1839 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
1840
1841 NSString *custom([Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")]);
1842
1843 $drawLabel$(label, [self bounds], style, custom);
1844 }
1845
1846 MSInstanceMessage0(CGImageRef, SBIconLabel, buildLabelImage) {
1847 bool docked((MSHookIvar<unsigned>(self, "_inDock") & 0x2) != 0);
1848
1849 WBStringDrawingState labelState = {NULL, 0, @""
1850 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1851
1852 stringDrawingState_ = &labelState;
1853
1854 //NSLog(@"XXX: +");
1855 CGImageRef image(MSOldCall());
1856 //NSLog(@"XXX: -");
1857
1858 stringDrawingState_ = NULL;
1859 return image;
1860 }
1861
1862 static bool wb$inDock(id parameters) {
1863 return [$objc_getAssociatedObject(parameters, @selector(wb$inDock)) boolValue];
1864 }
1865
1866 MSInstanceMessage0(NSUInteger, SBIconLabelImageParameters, hash) {
1867 return MSOldCall() + (wb$inDock(self) ? 0xdeadbeef : 0xd15ea5e);
1868 }
1869
1870 MSClassMessage2(id, SBIconView, _labelImageParametersForIcon,location, id, icon, int, location) {
1871 if (id parameters = MSOldCall(icon, location)) {
1872 $objc_setAssociatedObject(parameters, @selector(wb$inDock), [NSNumber numberWithBool:(location == 1)], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1873 return parameters;
1874 } return nil;
1875 }
1876
1877 MSInstanceMessage0(id, SBIconView, _labelImageParameters) {
1878 if (id parameters = MSOldCall()) {
1879 int &location(MSHookIvar<int>(self, "_iconLocation"));
1880 if (&location != NULL)
1881 $objc_setAssociatedObject(parameters, @selector(wb$inDock), [NSNumber numberWithBool:(location == 3)], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1882 return parameters;
1883 } return nil;
1884 }
1885
1886 MSClassMessage1(UIImage *, SBIconLabelImage, _drawLabelImageForParameters, id, parameters) {
1887 bool docked(wb$inDock(parameters));
1888
1889 WBStringDrawingState labelState = {NULL, 0, @""
1890 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1891
1892 stringDrawingState_ = &labelState;
1893
1894 //NSLog(@"XXX: +");
1895 UIImage *image(MSOldCall(parameters));
1896 //NSLog(@"XXX: -");
1897
1898 stringDrawingState_ = NULL;
1899 return image;
1900 }
1901
1902 // ChatKit {{{
1903 MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1904 if ((self = MSOldCall(frame, delegate)) != nil) {
1905 [self setBackgroundColor:[UIColor clearColor]];
1906 } return self;
1907 }
1908
1909 MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1910 return SMSBackgrounded_ ? NO : MSOldCall();
1911 }
1912
1913 MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1914 [self wb$setBackgroundColor:[UIColor clearColor]];
1915 return MSOldCall();
1916 }
1917
1918 MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1919 MSOldCall(balloon);
1920 [balloon setBackgroundColor:[UIColor clearColor]];
1921 }
1922
1923 MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1924 MSOldCall([UIColor clearColor]);
1925 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1926 }
1927
1928 // iOS >= 5.0
1929 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1930 if ((self = MSOldCall(style, reuse)) != nil) {
1931 [self setBackgroundColor:[UIColor clearColor]];
1932 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
1933 } return self;
1934 }
1935
1936 // iOS << 5.0
1937 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1938 if ((self = MSOldCall(style, reuse)) != nil) {
1939 [self setBackgroundColor:[UIColor clearColor]];
1940 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1941 } return self;
1942 }
1943
1944 MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1945 if ((self = MSOldCall(style, reuse)) != nil) {
1946 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1947 [_label setBackgroundColor:[UIColor clearColor]];
1948 } return self;
1949 }
1950
1951 MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1952 MSOldCall(UITableViewCellSeparatorStyleNone);
1953 }
1954
1955 MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1956 if ((self = MSOldCall(frame, style)) != nil) {
1957 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1958 } return self;
1959 }
1960
1961 MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1962 MSOldCall();
1963
1964 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1965 if (UIImage *image = $getImage$(path)) {
1966 SMSBackgrounded_ = true;
1967
1968 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
1969 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
1970 UIView *table;
1971 if (&_transcriptTable != NULL)
1972 table = _transcriptTable;
1973 else if (&_transcriptLayer != NULL)
1974 table = _transcriptLayer;
1975 else
1976 table = nil;
1977
1978 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
1979 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
1980
1981 if (table == nil)
1982 [placard insertSubview:background atIndex:0];
1983 else {
1984 [table setBackgroundColor:[UIColor clearColor]];
1985 [placard insertSubview:background belowSubview:table];
1986 }
1987 }
1988 }
1989 // }}}
1990
1991 template <typename Original_>
1992 static UIImage *WBCacheUIImage(const Original_ &original, NSString *name, NSString *key) {
1993 if ([name rangeOfString:@"."].location == NSNotFound)
1994 name = [name stringByAppendingString:@".png"];
1995 UIImage *image(WBCacheImage(original, [=](){ return $pathForFile$inBundle$(name, _UIKitBundle(), true, true); }, key));
1996 if (image != nil && UIDebug_) {
1997 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1998 if (![Manager_ fileExistsAtPath:path])
1999 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
2000 } return image;
2001 }
2002
2003 // %hook _UIImageWithName() {{{
2004 MSHook(UIImage *, _UIImageWithName, NSString *name) {
2005 if (name == nil)
2006 return nil;
2007 if (Debug_)
2008 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
2009 return WBCacheUIImage(
2010 [=](){ return __UIImageWithName(name); },
2011 name, [NSString stringWithFormat:@"I:%@", name]);
2012 }
2013 // }}}
2014 // %hook _UIImageWithNameInDomain() {{{
2015 MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
2016 if (Debug_)
2017 NSLog(@"WB:Debug: _UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
2018 return WBCacheImage(
2019 [=](){ return __UIImageWithNameInDomain(name, domain); },
2020 [=](){ return $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])); },
2021 [NSString stringWithFormat:@"D:%zu:%@%@", size_t([domain length]), domain, name]);
2022 }
2023 // }}}
2024 // %hook _UIImageWithDeviceUsingCurrentIdiom() {{{
2025 MSHook(UIImage *, _UIImageWithNameUsingCurrentIdiom, NSString *name) {
2026 if (Debug_)
2027 NSLog(@"WB:Debug: _UIImageWithNameUsingCurrentIdiom(\"%@\")", name);
2028 return WBCacheUIImage(
2029 [=](){ return __UIImageWithNameUsingCurrentIdiom(name); },
2030 name, [NSString stringWithFormat:@"I:%@", name]);
2031 }
2032 // }}}
2033 // %hook _UIImageWithDeviceSpecificName() {{{
2034 MSHook(UIImage *, _UIImageWithDeviceSpecificName, NSString *name) {
2035 if (Debug_)
2036 NSLog(@"WB:Debug: _UIImageWithDeviceSpecificName(\"%@\")", name);
2037 return WBCacheUIImage(
2038 [=](){ return __UIImageWithDeviceSpecificName(name); },
2039 name, [NSString stringWithFormat:@"S:%@", name]);
2040 }
2041 // }}}
2042
2043 // %hook GSFontCreateWithName() {{{
2044 MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
2045 if (Debug_)
2046 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
2047 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
2048 name = [font UTF8String];
2049 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
2050 // size *= [scale floatValue];
2051 return _GSFontCreateWithName(name, traits, size);
2052 }
2053 // }}}
2054
2055 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
2056
2057 static bool GetFileNameForThisAction$(bool value, unsigned long a0, char *a1, unsigned long a2, bool &a3) {
2058 if (Debug_)
2059 NSLog(@"WB:Debug:GetFileNameForThisAction(%lu, %s, %lu, %u) = %u", a0, value ? a1 : NULL, a2, a3, value);
2060
2061 if (value) {
2062 NSString *path = [NSString stringWithUTF8String:a1];
2063 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
2064 NSString *file = [path substringFromIndex:31];
2065 for (NSString *theme in Themes_) {
2066 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
2067 if ([Manager_ fileExistsAtPath:path]) {
2068 strcpy(a1, [path UTF8String]);
2069 break;
2070 }
2071 }
2072 }
2073 }
2074 return value;
2075 }
2076
2077 MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a3) {
2078 bool value(__Z24GetFileNameForThisActionmPcRb(a0, a1, a3));
2079 return GetFileNameForThisAction$(value, a0, a1, 0, a3);
2080 }
2081
2082 MSHook(bool, _Z24GetFileNameForThisActionmPcmRb, unsigned long a0, char *a1, unsigned long a2, bool &a3) {
2083 bool value(__Z24GetFileNameForThisActionmPcmRb(a0, a1, a2, a3));
2084 return GetFileNameForThisAction$(value, a0, a1, a2, a3);
2085 }
2086
2087 static void ChangeWallpaper(
2088 CFNotificationCenterRef center,
2089 void *observer,
2090 CFStringRef name,
2091 const void *object,
2092 CFDictionaryRef info
2093 ) {
2094 if (Debug_)
2095 NSLog(@"WB:Debug:ChangeWallpaper!");
2096
2097 UIImage *image;
2098 if (WallpaperFile_ != nil) {
2099 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
2100 if (image != nil)
2101 image = [image autorelease];
2102 } else image = nil;
2103
2104 if (WallpaperImage_ != nil)
2105 [WallpaperImage_ setImage:image];
2106 if (WallpaperPage_ != nil)
2107 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
2108
2109 }
2110
2111 MSHook(NSArray *, CPBitmapCreateImagesFromPath, NSString *path, NSDictionary **names, void *arg2, void *arg3) {
2112 NSArray *images(_CPBitmapCreateImagesFromPath(path, names, arg2, arg3));
2113 if (images != NULL && *names != nil && CFGetTypeID((CFTypeRef) *names) == CFDictionaryGetTypeID()) {
2114 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:path]) {
2115 NSMutableArray *copy([images mutableCopy]);
2116 [images release];
2117 images = copy;
2118
2119 NSString *file([path stringByResolvingSymlinksInPath]);
2120 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
2121 if ([file hasPrefix:prefix]) {
2122 NSUInteger length([prefix length]);
2123 if (length != [file length]) {
2124 NSEnumerator *enumerator([*names keyEnumerator]);
2125 while (NSString *name = [enumerator nextObject]) {
2126 NSString *png([name stringByAppendingString:@".png"]);
2127 if (NSString *themed = $pathForFile$inBundle$(png, bundle, false, true)) {
2128 NSUInteger index([[*names objectForKey:name] intValue]);
2129 UIImage *image($getImage$(themed));
2130 CGImageRef cg([image CGImage]);
2131 [copy replaceObjectAtIndex:index withObject:(id)cg];
2132 }
2133 }
2134 }
2135 }
2136 }
2137 } return images;
2138 }
2139
2140 MSHook(void, BKSDisplayServicesSetSystemAppExitedImagePath, NSString *path) {
2141 if (NSString *themed = $getTheme$($useScale$([NSArray arrayWithObject:@"SystemAppExited.png"])))
2142 path = themed;
2143 _BKSDisplayServicesSetSystemAppExitedImagePath(path);
2144 }
2145
2146 #define WBRename(name, sel, imp) \
2147 MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp, &_ ## name ## $ ## imp)
2148
2149 template <typename Type_>
2150 static void msset(Type_ &function, MSImageRef image, const char *name) {
2151 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
2152 }
2153
2154 #define WBHookSymbol(image, function) \
2155 msset(function, image, "_" #function)
2156
2157 template <typename Type_>
2158 static void dlset(Type_ &function, const char *name) {
2159 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
2160 }
2161
2162 // %hook CGImageReadCreateWithFile() {{{
2163 MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
2164 if (Debug_)
2165 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
2166 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2167 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
2168 [pool release];
2169 return value;
2170 }
2171
2172 MSHook(void *, CGImageSourceCreateWithFile, NSString *path, NSDictionary *options) {
2173 if (Debug_)
2174 NSLog(@"WB:Debug: CGImageSourceCreateWithFile(%@, %@)", path, options);
2175 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2176 void *value(_CGImageSourceCreateWithFile([path wb$themedPath], options));
2177 [pool release];
2178 return value;
2179 }
2180
2181 MSHook(void *, CGImageSourceCreateWithURL, NSURL *url, NSDictionary *options) {
2182 if (Debug_)
2183 NSLog(@"WB:Debug: CGImageSourceCreateWithURL(%@, %@)", url, options);
2184 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2185 if ([url isFileURL])
2186 url = [NSURL fileURLWithPath:[[url path] wb$themedPath]];
2187 void *value(_CGImageSourceCreateWithURL(url, options));
2188 [pool release];
2189 return value;
2190 }
2191 // }}}
2192
2193 static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
2194 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
2195 if (style == nil || [style length] == 0)
2196 style = @"font-family: Helvetica; font-size: 12px";
2197 //NSLog(@"XXX:drawP(%@ | %@)", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
2198 [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
2199 }
2200
2201 static void NSString$drawInRect$withStyle$(NSString *self, SEL _cmd, CGRect rect, NSString *style) {
2202 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
2203 if (style == nil || [style length] == 0)
2204 style = @"font-family: Helvetica; font-size: 12px";
2205 //NSLog(@"XXX:drawR(%@ | %@)", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
2206 return [[WBMarkup sharedMarkup] drawString:self inRect:rect withStyle:style];
2207 }
2208
2209 static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, CGFloat width) {
2210 if (style == nil || [style length] == 0)
2211 style = @"font-family: Helvetica; font-size: 12px";
2212 CGSize size([[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width]);
2213 //NSLog(@"XXX:size(%@ | %@) = [%g %g]", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "], size.width, size.height);
2214 return size;
2215 }
2216
2217 static void SBInitialize() {
2218 if (SummerBoard_) {
2219 WBRename(SBApplication, pathForIcon, pathForIcon);
2220 WBRename(SBApplicationIcon, icon, icon);
2221 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
2222 }
2223
2224 WBRename(SBBookmarkIcon, icon, icon);
2225 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
2226 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
2227 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
2228 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
2229
2230 WBRename(SBWidgetApplicationIcon, icon, icon);
2231
2232 WBRename(SBDockIconListView, setFrame:, setFrame$);
2233 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
2234
2235 if (kCFCoreFoundationVersionNumber < 600 || SummerBoard_)
2236 WBRename(SBIconLabel, drawRect:, drawRect$);
2237 else if (kCFCoreFoundationVersionNumber < 700) {
2238 WBRename(SBIconLabel, buildLabelImage, buildLabelImage);
2239 } else {
2240 WBRename(SBIconLabelImageParameters, hash, hash);
2241 WBRename($SBIconView, _labelImageParametersForIcon:location:, _labelImageParametersForIcon$location$);
2242 WBRename(SBIconView, _labelImageParameters, _labelImageParameters);
2243 WBRename($SBIconLabelImage, _drawLabelImageForParameters:, _drawLabelImageForParameters$);
2244 }
2245
2246 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
2247 WBRename(SBIconLabel, setInDock:, setInDock$);
2248
2249 WBRename(SBIconList, didMoveToSuperview, didMoveToSuperview);
2250 WBRename(SBIconList, setFrame:, setFrame$);
2251
2252 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
2253 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
2254 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
2255 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
2256
2257 if (kCFCoreFoundationVersionNumber < 800) {
2258 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
2259 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
2260 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
2261 }
2262
2263 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
2264
2265 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
2266 if (kCFCoreFoundationVersionNumber >= 700)
2267 WBRename(SBAwayView, _addSubview:positioned:relativeTo:, _addSubview$positioned$relativeTo$);
2268
2269 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
2270 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
2271 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
2272 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
2273 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
2274 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
2275 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
2276 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
2277
2278 if (SummerBoard_)
2279 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
2280
2281 if (kCFCoreFoundationVersionNumber >= 800) {
2282 WBRename(NSString, drawInRect:withAttributes:, drawInRect$withAttributes$);
2283 WBRename(NSString, boundingRectWithSize:options:attributes:context:, boundingRectWithSize$options$attributes$context$);
2284 }
2285 }
2286
2287 /*MSHook(int, open, const char *path, int oflag, mode_t mode) {
2288 int fd(_open(path, oflag, mode));
2289
2290 static bool no(false);
2291 if (no) return fd;
2292 no = true;
2293
2294 if (strstr(path, "/icon") != NULL)
2295 MSHookProcess(-1, "");
2296
2297 if (fd == -1 && errno == EFAULT)
2298 NSLog(@"open(%p, %#x, %#o) = %d\n", path, oflag, mode, fd);
2299 else
2300 NSLog(@"open(\"%s\", %#x, %#o) = %d\n", path, oflag, mode, fd);
2301
2302 no = false;
2303 return fd;
2304 }*/
2305
2306 MSInitialize {
2307 $objc_setAssociatedObject = reinterpret_cast<void (*)(id, void *, id value, objc_AssociationPolicy)>(dlsym(RTLD_DEFAULT, "objc_setAssociatedObject"));
2308 $objc_getAssociatedObject = reinterpret_cast<id (*)(id, void *)>(dlsym(RTLD_DEFAULT, "objc_getAssociatedObject"));
2309 $objc_removeAssociatedObjects = reinterpret_cast<void (*)(id)>(dlsym(RTLD_DEFAULT, "objc_removeAssociatedObjects"));
2310
2311 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2312
2313 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
2314 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
2315
2316 Manager_ = [[NSFileManager defaultManager] retain];
2317 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
2318
2319 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
2320
2321 // Load Settings.plist {{{
2322 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
2323 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
2324 SummerBoard_ = [value boolValue];
2325 else
2326 SummerBoard_ = true;
2327
2328 if (NSNumber *value = [settings objectForKey:@"Debug"])
2329 Debug_ = [value boolValue];
2330 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
2331 UIDebug_ = [value boolValue];
2332
2333 NSArray *themes([settings objectForKey:@"Themes"]);
2334 if (themes == nil)
2335 if (NSString *theme = [settings objectForKey:@"Theme"])
2336 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
2337 theme, @"Name",
2338 [NSNumber numberWithBool:true], @"Active",
2339 nil]];
2340
2341 if (themes != nil)
2342 for (NSDictionary *theme in themes) {
2343 NSNumber *active([theme objectForKey:@"Active"]);
2344 if (![active boolValue])
2345 continue;
2346
2347 NSString *name([theme objectForKey:@"Name"]);
2348 if (name == nil)
2349 continue;
2350
2351 #define testForTheme(format...) \
2352 { \
2353 NSString *path = [NSString stringWithFormat:format]; \
2354 if ([Manager_ fileExistsAtPath:path]) { \
2355 [Themes_ addObject:path]; \
2356 continue; \
2357 } \
2358 }
2359
2360 testForTheme(@"/Library/Themes/%@.theme", name)
2361 testForTheme(@"/Library/Themes/%@", name)
2362 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
2363
2364 }
2365 }
2366 // }}}
2367 // Merge Info.plist {{{
2368 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2369
2370 for (NSString *theme in Themes_)
2371 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
2372 for (NSString *key in [info allKeys])
2373 if ([Info_ objectForKey:key] == nil)
2374 [Info_ setObject:[info objectForKey:key] forKey:key];
2375 // }}}
2376
2377 // AppSupport {{{
2378 if (MSImageRef image = MSGetImageByName("/System/Library/PrivateFrameworks/AppSupport.framework/AppSupport")) {
2379 NSArray *(*CPBitmapCreateImagesFromPath)(NSString *, NSDictionary **, void *, void *);
2380 msset(CPBitmapCreateImagesFromPath, image, "_CPBitmapCreateImagesFromPath");
2381 MSHookFunction(CPBitmapCreateImagesFromPath, MSHake(CPBitmapCreateImagesFromPath));
2382 }
2383 // }}}
2384 // AudioToolbox {{{
2385 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
2386 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long, char *, bool &);
2387 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
2388 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
2389
2390 bool (*_Z24GetFileNameForThisActionmPcmRb)(unsigned long, char *, unsigned long, bool &);
2391 msset(_Z24GetFileNameForThisActionmPcmRb, image, "__Z24GetFileNameForThisActionmPcmRb");
2392 MSHookFunction(_Z24GetFileNameForThisActionmPcmRb, &$_Z24GetFileNameForThisActionmPcmRb, &__Z24GetFileNameForThisActionmPcmRb);
2393 }
2394 // }}}
2395 // BackBoardServices {{{
2396 if (MSImageRef image = MSGetImageByName("/System/Library/PrivateFrameworks/BackBoardServices.framework/BackBoardServices")) {
2397 void (*BKSDisplayServicesSetSystemAppExitedImagePath)(NSString *path);
2398 msset(BKSDisplayServicesSetSystemAppExitedImagePath, image, "_BKSDisplayServicesSetSystemAppExitedImagePath");
2399 MSHookFunction(BKSDisplayServicesSetSystemAppExitedImagePath, MSHake(BKSDisplayServicesSetSystemAppExitedImagePath));
2400 }
2401 // }}}
2402 // GraphicsServices {{{
2403 if (true) {
2404 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
2405 }
2406 // }}}
2407 // ImageIO {{{
2408 MSImageRef imageio = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO");
2409 if (imageio == NULL)
2410 imageio = MSGetImageByName("/System/Library/PrivateFrameworks/ImageIO.framework/ImageIO");
2411 if (MSImageRef image = imageio) {
2412 void *(*CGImageReadCreateWithFile)(NSString *, int) = NULL;
2413 if (kCFCoreFoundationVersionNumber > 700) // XXX: iOS 6.x
2414 CGImageReadCreateWithFile = NULL;
2415 else {
2416 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
2417 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
2418 }
2419
2420 if (CGImageReadCreateWithFile == NULL) {
2421 void *(*CGImageSourceCreateWithFile)(NSString *, NSDictionary *);
2422 msset(CGImageSourceCreateWithFile, image, "_CGImageSourceCreateWithFile");
2423 MSHookFunction(CGImageSourceCreateWithFile, MSHake(CGImageSourceCreateWithFile));
2424
2425 void *(*CGImageSourceCreateWithURL)(NSURL *, NSDictionary *);
2426 msset(CGImageSourceCreateWithURL, image, "_CGImageSourceCreateWithURL");
2427 MSHookFunction(CGImageSourceCreateWithURL, MSHake(CGImageSourceCreateWithURL));
2428 }
2429 }
2430 // }}}
2431 // SpringBoard {{{
2432 if (SpringBoard_) {
2433 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
2434 Papered_ = $getTheme$(Wallpapers_) != nil;
2435 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
2436
2437 CFNotificationCenterAddObserver(
2438 CFNotificationCenterGetDarwinNotifyCenter(),
2439 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, CFNotificationSuspensionBehaviorCoalesce
2440 );
2441
2442 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
2443 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
2444 if (MediaPlayer != nil)
2445 [MediaPlayer load];
2446
2447 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
2448 $MPVideoView = objc_getClass("MPVideoView");
2449 }
2450
2451 SBInitialize();
2452 }
2453 // }}}
2454 // UIKit {{{
2455 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/UIKit.framework/UIKit")) {
2456 #ifdef __LP64__
2457 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v40@0:8{CGPoint=dd}16@32");
2458 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v56@0:8{CGRect={CGSize=dd}{CGSize=dd}}16@48");
2459 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=dd}32@0:8@16d24");
2460 #else
2461 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
2462 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v28@0:4{CGRect={CGSize=ff}{CGSize=ff}}8@24");
2463 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
2464 #endif
2465
2466 WBHookSymbol(image, _UIKitBundle);
2467
2468 MSHookFunction(_UIImageWithName, MSHake(_UIImageWithName));
2469
2470 WBHookSymbol(image, _UIApplicationImageWithName);
2471 MSHookFunction(_UIApplicationImageWithName, MSHake(_UIApplicationImageWithName));
2472
2473 WBHookSymbol(image, _UIImageWithNameInDomain);
2474 MSHookFunction(_UIImageWithNameInDomain, MSHake(_UIImageWithNameInDomain));
2475
2476 WBHookSymbol(image, _UIImageWithNameUsingCurrentIdiom);
2477 MSHookFunction(_UIImageWithNameUsingCurrentIdiom, MSHake(_UIImageWithNameUsingCurrentIdiom));
2478
2479 WBHookSymbol(image, _UIImageWithDeviceSpecificName);
2480 MSHookFunction(_UIImageWithDeviceSpecificName, MSHake(_UIImageWithDeviceSpecificName));
2481
2482 SEL includeEmoji(@selector(_legacy_drawAtPoint:forWidth:withFont:lineBreakMode:letterSpacing:includeEmoji:));
2483 if (![@"" respondsToSelector:includeEmoji])
2484 includeEmoji = @selector(drawAtPoint:forWidth:withFont:lineBreakMode:letterSpacing:includeEmoji:);
2485 MSHookMessage($NSString, includeEmoji, MSHake(NSString$drawAtPoint$forWidth$withFont$lineBreakMode$letterSpacing$includeEmoji$));
2486
2487 SEL letterSpacing(@selector(_legacy_sizeWithFont:forWidth:lineBreakMode:letterSpacing:));
2488 if (![@"" respondsToSelector:letterSpacing])
2489 letterSpacing = @selector(sizeWithFont:forWidth:lineBreakMode:letterSpacing:);
2490 MSHookMessage($NSString, letterSpacing, MSHake(NSString$sizeWithFont$forWidth$lineBreakMode$letterSpacing$));
2491
2492 SEL sizeWithFont(@selector(_legacy_sizeWithFont:));
2493 if (![@"" respondsToSelector:sizeWithFont])
2494 sizeWithFont = @selector(sizeWithFont:);
2495 MSHookMessage($NSString, sizeWithFont, MSHake(NSString$sizeWithFont$));
2496 }
2497 // }}}
2498
2499 //MSHookFunction(reinterpret_cast<int (*)(const char *, int, mode_t)>(&open), MSHake(open));
2500
2501 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
2502 NSError *error(nil);
2503 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
2504 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
2505 nil] error:&error])
2506 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);
2507 }
2508
2509 [pool release];
2510 }