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