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