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