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