]> git.saurik.com Git - winterboard.git/blame - Library.mm
Reimplement iOS 5.x icon label styling.
[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
JF
202static bool Engineer_ = false;
203static bool SummerBoard_ = true;
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
19fe3063
JF
679static struct WBStringDrawingState {
680 WBStringDrawingState *next_;
cc5f5e5d 681 unsigned count_;
1ed87fae
JF
682 NSString *base_;
683 NSString *info_;
19fe3063
JF
684} *stringDrawingState_;
685
b3f846db 686MSInstanceMessageHook6(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode,letterSpacing,includeEmoji, CGPoint, point, float, width, UIFont *, font, int, mode, float, spacing, BOOL, emoji) {
cc5f5e5d
JF
687 WBStringDrawingState *state(stringDrawingState_);
688 if (state == NULL)
b3f846db 689 return MSOldCall(point, width, font, mode, spacing, emoji);
19fe3063 690
cc5f5e5d
JF
691 if (--state->count_ == 0)
692 stringDrawingState_ = state->next_;
693 if (state->info_ == nil)
b3f846db 694 return MSOldCall(point, width, font, mode, spacing, emoji);
19fe3063 695
cc5f5e5d
JF
696 NSString *info([Info_ objectForKey:state->info_]);
697 if (info == nil)
b3f846db 698 return MSOldCall(point, width, font, mode, spacing, emoji);
19fe3063 699
cc5f5e5d 700 NSString *base(state->base_ ?: @"");
1ed87fae 701 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]];
19fe3063
JF
702 return CGSizeZero;
703}
704
b3f846db 705MSInstanceMessageHook4(CGSize, NSString, sizeWithFont,forWidth,lineBreakMode,letterSpacing, UIFont *, font, float, width, int, mode, float, spacing) {
cc5f5e5d
JF
706 WBStringDrawingState *state(stringDrawingState_);
707 if (state == NULL)
b3f846db 708 return MSOldCall(font, width, mode, spacing);
19fe3063 709
cc5f5e5d
JF
710 if (--state->count_ == 0)
711 stringDrawingState_ = state->next_;
712 if (state->info_ == nil)
b3f846db 713 return MSOldCall(font, width, mode, spacing);
19fe3063 714
cc5f5e5d
JF
715 NSString *info([Info_ objectForKey:state->info_]);
716 if (info == nil)
b3f846db 717 return MSOldCall(font, width, mode, spacing);
19fe3063 718
cc5f5e5d 719 NSString *base(state->base_ ?: @"");
b3f846db 720 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info] forWidth:width];
19fe3063
JF
721}
722
cc5f5e5d
JF
723MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) {
724 WBStringDrawingState *state(stringDrawingState_);
725 if (state == NULL)
726 return MSOldCall(font);
727
728 if (--state->count_ == 0)
729 stringDrawingState_ = state->next_;
730 if (state->info_ == nil)
731 return MSOldCall(font);
732
733 NSString *info([Info_ objectForKey:state->info_]);
734 if (info == nil)
735 return MSOldCall(font);
736
737 NSString *base(state->base_ ?: @"");
738 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info] forWidth:65535];
739}
740
19fe3063 741MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
cc5f5e5d 742 WBStringDrawingState badgeState = {NULL, 1, @""
19fe3063
JF
743 "color: white;"
744 , @"BadgeStyle"};
745
746 stringDrawingState_ = &badgeState;
747
748 UIImage *image(MSOldCall(text));
749
750 stringDrawingState_ = NULL;
751 return image;
752}
753
754MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
cc5f5e5d 755 WBStringDrawingState dayState = {NULL, 2, @""
19fe3063 756 "color: white;"
1ed87fae 757 // XXX: this is only correct on an iPod dock
19fe3063
JF
758 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
759 , @"CalendarIconDayStyle"};
760
cc5f5e5d
JF
761 WBStringDrawingState sizeState = {&dayState, 7, nil, nil};
762
763 WBStringDrawingState dateState = {&sizeState, 2, @""
19fe3063
JF
764 "color: #333333;"
765 , @"CalendarIconDateStyle"};
766
767 stringDrawingState_ = &dateState;
768
769 UIImage *image(MSOldCall(type));
770
771 stringDrawingState_ = NULL;
772 return image;
773}
774
0316ebc4 775MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
4668cd8e
JF
776 NSBundle *bundle([NSBundle mainBundle]);
777
e6f0817b
JF
778 CFLocaleRef locale(CFLocaleCopyCurrent());
779 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
780 CFRelease(locale);
781
782 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
783
77d89d52 784 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
e6f0817b 785 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
44aa4549 786 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
e6f0817b
JF
787 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
788
789 CFRelease(now);
790
791 CFRelease(formatter);
792
c79980f5 793 NSString *datestyle([@""
e6f0817b
JF
794 "font-family: Helvetica; "
795 "font-weight: bold; "
e6f0817b
JF
796 "color: #333333; "
797 "alpha: 1.0; "
1d3b613f 798 "" stringByAppendingString:(IsWild_
c79980f5
JF
799 ? @"font-size: 54px; "
800 : @"font-size: 39px; "
801 )]);
e6f0817b 802
c79980f5 803 NSString *daystyle([@""
e6f0817b
JF
804 "font-family: Helvetica; "
805 "font-weight: bold; "
e6f0817b
JF
806 "color: white; "
807 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
1d3b613f 808 "" stringByAppendingString:(IsWild_
c79980f5
JF
809 ? @"font-size: 11px; "
810 : @"font-size: 9px; "
811 )]);
e6f0817b
JF
812
813 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
814 datestyle = [datestyle stringByAppendingString:style];
815 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
816 daystyle = [daystyle stringByAppendingString:style];
817
cf31d246 818 float width([self bounds].size.width);
4668cd8e
JF
819 float leeway(10);
820 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
821 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
e6f0817b 822
77d89d52 823 unsigned base0(IsWild_ ? 89 : 70);
c79980f5 824 if ($GSFontGetUseLegacyFontMetrics())
77d89d52
JF
825 base0 = base0 + 1;
826 unsigned base1(IsWild_ ? 18 : 16);
827
828 if (Four_) {
829 ++base0;
830 ++base1;
831 }
81decb42 832
e6f0817b 833 [(NSString *)date drawAtPoint:CGPointMake(
77d89d52 834 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
e6f0817b
JF
835 ) withStyle:datestyle];
836
837 [(NSString *)day drawAtPoint:CGPointMake(
77d89d52 838 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
e6f0817b
JF
839 ) withStyle:daystyle];
840
841 CFRelease(date);
842 CFRelease(day);
843}
844
e079e414
JF
845// %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
846void $setBarStyle$_(NSString *name, int &style) {
847 if (Debug_)
848 NSLog(@"WB:Debug:%@Style:%d", name, style);
849 NSNumber *number = nil;
850 if (number == nil)
851 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
852 if (number == nil)
853 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
854 if (number != nil) {
d5fb6e01 855 style = [number intValue];
e079e414
JF
856 if (Debug_)
857 NSLog(@"WB:Debug:%@Style=%d", name, style);
858 }
26c43b47
JF
859}
860
e079e414 861MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
0316ebc4 862 $setBarStyle$_(@"Toolbar", style);
e079e414 863 return MSOldCall(style);
95a5777b
JF
864}
865
e079e414 866MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
0316ebc4 867 $setBarStyle$_(@"NavigationBar", style);
e079e414 868 return MSOldCall(style);
26c43b47 869}
e079e414 870// }}}
26c43b47 871
0316ebc4 872MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
2acbe5b8 873 [[self superview] setBackgroundColor:[UIColor clearColor]];
0316ebc4 874 _SBButtonBar$didMoveToSuperview(self, sel);
08454e3a 875}
62b2dbad 876
0316ebc4
JF
877MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
878 [[self superview] setBackgroundColor:[UIColor clearColor]];
879 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
880}
881
4668cd8e 882static NSArray *Wallpapers_;
1d3b613f 883static bool Papered_;
77d89d52 884static bool Docked_;
6de35b7f 885static bool SMSBackgrounded_;
4668cd8e 886static NSString *WallpaperFile_;
502d350e
JF
887static UIImageView *WallpaperImage_;
888static UIWebDocumentView *WallpaperPage_;
889static NSURL *WallpaperURL_;
95a5777b 890
4668cd8e
JF
891#define _release(object) \
892 do if (object != nil) { \
893 [object release]; \
894 object = nil; \
895 } while (false)
896
e079e414 897static UIImage *$getImage$(NSString *path) {
e079e414
JF
898 UIImage *image([UIImage imageWithContentsOfFile:path]);
899
5b21732c 900 unsigned scale($getScale$(path));
e079e414
JF
901 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
902 [image setScale:scale];
903
904 return image;
905}
906
eae989a3
JF
907static UIImage *$getDefaultDesktopImage$() {
908 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
909 return $getImage$(path);
910 return nil;
911}
912
913MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
914 return $getDefaultDesktopImage$() ?: MSOldCall();
915}
916
917MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
918 return $getDefaultDesktopImage$() ?: MSOldCall();
919}
920
921MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
922 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
923 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
924 if (UIImage *image = $getDefaultDesktopImage$()) {
925 [self setImage:image];
926 return;
927 }
928
929 break;
930 }
931
932 MSOldCall();
933}
934
e079e414
JF
935// %hook -[SBUIController init] {{{
936MSInstanceMessageHook0(id, SBUIController, init) {
937 self = MSOldCall();
d5168fd6
JF
938 if (self == nil)
939 return nil;
940
39271ad2 941 NSString *paper($getTheme$(Wallpapers_));
ecf154db
JF
942 if (paper != nil)
943 paper = [paper stringByDeletingLastPathComponent];
e079e414 944
609e1cd8
JF
945 {
946 size_t size;
947 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
948 char *machine = new char[size];
949
950 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
951 perror("sysctlbyname(\"hw.machine\", ?)");
952 delete [] machine;
953 machine = NULL;
954 }
955
956 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
957 }
226d2af9 958
0137e6de
JF
959 if (Debug_)
960 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
961
e079e414 962 if (paper != nil) {
55e82d74 963 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
1d3b613f
JF
964 if (&_wallpaperView != NULL) {
965 [_wallpaperView removeFromSuperview];
966 [_wallpaperView release];
967 _wallpaperView = nil;
968 }
969 }
970
44aa4549 971 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
69550bfb
JF
972 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
973
77d89d52 974 UIView **player;
44aa4549 975 if (&_contentLayer != NULL)
77d89d52 976 player = &_contentLayer;
44aa4549 977 else if (&_contentView != NULL)
77d89d52 978 player = &_contentView;
44aa4549 979 else
77d89d52 980 player = NULL;
77d89d52 981 UIView *layer(player == NULL ? nil : *player);
44aa4549 982
55e82d74
JF
983 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
984 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
985 [window setContentView:content];
986
987 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
988 [window setBackgroundColor:[_window backgroundColor]];
989 [_window setBackgroundColor:[UIColor clearColor]];
990
991 [window setLevel:-1000];
992 [window setHidden:NO];
1d3b613f 993
77d89d52
JF
994 /*if (player != NULL)
995 *player = content;*/
996
44aa4549
JF
997 [content setBackgroundColor:[layer backgroundColor]];
998 [layer setBackgroundColor:[UIColor clearColor]];
69550bfb 999
1d3b613f
JF
1000 UIView *indirect;
1001 if (!SummerBoard_ || !IsWild_)
1002 indirect = content;
1003 else {
1004 CGRect bounds([content bounds]);
c8fbf228 1005 bounds.origin.y = -30;
1d3b613f
JF
1006 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
1007 [content addSubview:indirect];
1008 [indirect zoomToScale:2.4];
1009 }
1010
4668cd8e
JF
1011 _release(WallpaperFile_);
1012 _release(WallpaperImage_);
1013 _release(WallpaperPage_);
1014 _release(WallpaperURL_);
1015
ecf154db
JF
1016 if (paper != nil) {
1017 NSArray *themes([NSArray arrayWithObject:paper]);
1018
1019 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
d806256e
JF
1020#if UseAVController
1021 NSError *error;
1022
1023 static AVController *controller_(nil);
1024 if (controller_ == nil) {
1025 AVQueue *queue([AVQueue avQueue]);
1026 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1027 }
1028
1029 AVQueue *queue([controller_ queue]);
1030
1d3b613f 1031 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
d806256e
JF
1032 [controller_ setLayer:[video _layer]];
1033
e079e414 1034 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
d806256e
JF
1035 [queue appendItem:item error:&error];
1036
1037 [controller_ play:&error];
1038#elif UseMPMoviePlayerController
e079e414 1039 NSURL *url([NSURL fileURLWithPath:path]);
265e19b2 1040 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
d806256e
JF
1041 controller.movieControlMode = MPMovieControlModeHidden;
1042 [controller play];
1043#else
1d3b613f 1044 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
e079e414 1045 [video setMovieWithPath:path];
4668cd8e 1046 [video setRepeatMode:1];
d806256e 1047 [video setRepeatGap:-1];
4668cd8e 1048 [video playFromBeginning];;
d806256e
JF
1049#endif
1050
1d3b613f 1051 [indirect addSubview:video];
4668cd8e 1052 }
d5fb6e01 1053
b461e3ec 1054 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
e079e414
JF
1055 if (UIImage *image = $getImage$(path)) {
1056 WallpaperFile_ = [path retain];
1057 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1058 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1059 [WallpaperImage_ setAlpha:[number floatValue]];
1060 [indirect addSubview:WallpaperImage_];
1061 }
4668cd8e 1062 }
394d1eb5 1063
b461e3ec 1064 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1d3b613f 1065 CGRect bounds = [indirect bounds];
502d350e 1066
4668cd8e
JF
1067 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1068 [view setAutoresizes:true];
502d350e 1069
4668cd8e 1070 WallpaperPage_ = [view retain];
e079e414 1071 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
394d1eb5 1072
4668cd8e
JF
1073 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1074
4668cd8e 1075 [view setBackgroundColor:[UIColor clearColor]];
1a4ffdf8
JF
1076 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1077 [view setDrawsBackground:NO];
1078 [[view webView] setDrawsBackground:NO];
394d1eb5 1079
1d3b613f 1080 [indirect addSubview:view];
4668cd8e 1081 }
08454e3a 1082 }
d5168fd6 1083
e079e414
JF
1084 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1085 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
5e5c7190
JF
1086 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1087 if ([Manager_ fileExistsAtPath:html]) {
1d3b613f 1088 CGRect bounds = [indirect bounds];
5e5c7190
JF
1089
1090 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1091 [view setAutoresizes:true];
1092
1093 NSURL *url = [NSURL fileURLWithPath:html];
1094 [view loadRequest:[NSURLRequest requestWithURL:url]];
1095
5e5c7190 1096 [view setBackgroundColor:[UIColor clearColor]];
1a4ffdf8
JF
1097 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1098 [view setDrawsBackground:NO];
1099 [[view webView] setDrawsBackground:NO];
5e5c7190 1100
1d3b613f 1101 [indirect addSubview:view];
5e5c7190
JF
1102 }
1103 }
1104
d5168fd6
JF
1105 return self;
1106}
e079e414 1107// }}}
d5168fd6 1108
9cfe3924 1109MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
502d350e 1110 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
2acbe5b8 1111 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
502d350e 1112
2acbe5b8
JF
1113 if (path != nil && _backgroundView != nil)
1114 path = nil;
502d350e 1115
9cfe3924 1116 _SBAwayView$updateDesktopImage$(self, sel, image);
502d350e
JF
1117
1118 if (path != nil) {
1119 CGRect bounds = [self bounds];
1120
2acbe5b8 1121 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
502d350e
JF
1122 [view setAutoresizes:true];
1123
1124 if (WallpaperPage_ != nil)
1125 [WallpaperPage_ release];
1126 WallpaperPage_ = [view retain];
1127
1128 if (WallpaperURL_ != nil)
1129 [WallpaperURL_ release];
1130 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1131
1132 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1133
1134 [[view webView] setDrawsBackground:false];
2acbe5b8 1135 [view setBackgroundColor:[UIColor clearColor]];
502d350e 1136
2acbe5b8 1137 [self insertSubview:view aboveSubview:_backgroundView];
ca13798d 1138 }
502d350e 1139}
ca13798d 1140
95a5777b 1141/*extern "C" CGColorRef CGGStateGetSystemColor(void *);
ca13798d
JF
1142extern "C" CGColorRef CGGStateGetFillColor(void *);
1143extern "C" CGColorRef CGGStateGetStrokeColor(void *);
95a5777b 1144extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
ca13798d 1145
cd6ad593
JF
1146/* WBTimeLabel {{{ */
1147@interface WBTimeLabel : NSProxy {
ca13798d
JF
1148 NSString *time_;
1149 _transient SBStatusBarTimeView *view_;
889cb4f2
JF
1150}
1151
ca13798d 1152- (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
889cb4f2
JF
1153
1154@end
1155
cd6ad593 1156@implementation WBTimeLabel
889cb4f2
JF
1157
1158- (void) dealloc {
ca13798d 1159 [time_ release];
889cb4f2
JF
1160 [super dealloc];
1161}
1162
ca13798d
JF
1163- (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1164 time_ = [time retain];
1165 view_ = view;
889cb4f2
JF
1166 return self;
1167}
1168
44aa4549
JF
1169- (NSString *) description {
1170 return time_;
1171}
1172
ca13798d
JF
1173WBDelegate(time_)
1174
1175- (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
d5fb6e01 1176 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
2acbe5b8 1177 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
d5fb6e01
JF
1178
1179 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1180 "font-family: Helvetica; "
1181 "font-weight: bold; "
1182 "font-size: 14px; "
1183 "color: %@; "
2acbe5b8 1184 "%@", _mode ? @"white" : @"black", custom]];
d5fb6e01
JF
1185
1186 return CGSizeZero;
1187 }
ca13798d
JF
1188
1189 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
889cb4f2
JF
1190}
1191
cd6ad593
JF
1192@end
1193/* }}} */
1194/* WBBadgeLabel {{{ */
1195@interface WBBadgeLabel : NSProxy {
1196 NSString *badge_;
1197}
1198
1199- (id) initWithBadge:(NSString *)badge;
29155933 1200- (NSString *) description;
cd6ad593 1201
ca13798d
JF
1202@end
1203
cd6ad593
JF
1204@implementation WBBadgeLabel
1205
1206- (void) dealloc {
1207 [badge_ release];
1208 [super dealloc];
889cb4f2
JF
1209}
1210
cd6ad593
JF
1211- (id) initWithBadge:(NSString *)badge {
1212 badge_ = [badge retain];
1213 return self;
1214}
1215
29155933
JF
1216- (NSString *) description {
1217 return [badge_ description];
1218}
1219
cd6ad593
JF
1220WBDelegate(badge_)
1221
1222- (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1223 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1224 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1225 "font-family: Helvetica; "
1226 "font-weight: bold; "
1227 "font-size: 17px; "
1228 "color: white; "
1229 "%@", custom]];
1230
1231 return CGSizeZero;
1232 }
1233
1234 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1235}
ca13798d
JF
1236
1237@end
cd6ad593
JF
1238/* }}} */
1239
e079e414
JF
1240// IconAlpha {{{
1241MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
8e4d2f42
JF
1242 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1243 alpha = [number floatValue];
e079e414 1244 return MSOldCall(alpha);
8e4d2f42
JF
1245}
1246
e079e414 1247MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
8e4d2f42
JF
1248 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1249 alpha = [number floatValue];
e079e414 1250 return MSOldCall(alpha);
8e4d2f42
JF
1251}
1252
e079e414
JF
1253MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1254 if ((self = MSOldCall()) != nil) {
8e4d2f42
JF
1255 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1256 // XXX: note: this is overridden above, which is silly
1257 float alpha([number floatValue]);
1258 [self setIconImageAlpha:alpha];
1259 [self setIconLabelAlpha:alpha];
1260 }
1261 } return self;
1262}
1263
e079e414 1264MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
b0d0c73f
JF
1265 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1266 alpha = [number floatValue];
e079e414 1267 return MSOldCall(alpha);
b0d0c73f 1268}
e079e414 1269// }}}
b0d0c73f 1270
0316ebc4
JF
1271MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1272 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
2acbe5b8
JF
1273 id &_badge(MSHookIvar<id>(self, "_badge"));
1274 if (_badge != nil)
1275 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1276 _badge = label;
cd6ad593
JF
1277 } return self;
1278}
ca13798d 1279
69550bfb 1280void SBStatusBarController$setStatusBarMode(int &mode) {
95a5777b
JF
1281 if (Debug_)
1282 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
502d350e 1283 if (mode < 100) // 104:hidden 105:glowing
95a5777b
JF
1284 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1285 mode = [number intValue];
d5fb6e01
JF
1286}
1287
69550bfb
JF
1288/*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1289 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1290 SBStatusBarController$setStatusBarMode(mode);
1291 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1292}*/
1293
1294MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
8b94f6b0 1295 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
69550bfb
JF
1296 SBStatusBarController$setStatusBarMode(mode);
1297 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1298}
1299
1300MSHook(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 1301 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
69550bfb 1302 SBStatusBarController$setStatusBarMode(mode);
8b94f6b0 1303 //NSLog(@"mode=%u", mode);
69550bfb
JF
1304 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1305}
1306
1307/*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
d5fb6e01
JF
1308 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1309 mode = [number intValue];
0316ebc4 1310 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
69550bfb 1311}*/
d5fb6e01 1312
0316ebc4
JF
1313MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1314 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
4668cd8e
JF
1315 if (Debug_)
1316 NSLog(@"operatorNameStyle= %@", style);
1317 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1318 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1319 return style;
1320}
1321
0316ebc4 1322MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
4668cd8e
JF
1323 if (Debug_)
1324 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
0316ebc4 1325 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
4668cd8e
JF
1326}
1327
0316ebc4
JF
1328// XXX: replace this with [SBStatusBarTimeView tile]
1329MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
2acbe5b8
JF
1330 id &_time(MSHookIvar<id>(self, "_time"));
1331 if (_time != nil && [_time class] != [WBTimeLabel class])
1332 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
0316ebc4 1333 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
ca13798d
JF
1334}
1335
98fe8d52 1336@interface UIView (WinterBoard)
a8d008e4 1337- (bool) wb$isWBImageView;
198eb03b 1338- (void) wb$logHierarchy;
096012f0 1339- (void) wb$setBackgroundColor:(UIColor *)color;
98fe8d52
JF
1340@end
1341
1342@implementation UIView (WinterBoard)
1343
a8d008e4 1344- (bool) wb$isWBImageView {
98fe8d52
JF
1345 return false;
1346}
1347
198eb03b
JF
1348- (void) wb$logHierarchy {
1349 WBLogHierarchy(self);
1350}
1351
096012f0
JF
1352- (void) wb$setBackgroundColor:(UIColor *)color {
1353 [self setBackgroundColor:color];
1354 for (UIView *child in [self subviews])
1355 [child wb$setBackgroundColor:color];
1356}
1357
98fe8d52
JF
1358@end
1359
a8d008e4
JF
1360@interface WBImageView : UIImageView {
1361}
1362
1363- (bool) wb$isWBImageView;
1364- (void) wb$updateFrame;
98fe8d52
JF
1365@end
1366
a8d008e4 1367@implementation WBImageView
98fe8d52 1368
a8d008e4 1369- (bool) wb$isWBImageView {
98fe8d52
JF
1370 return true;
1371}
1372
a8d008e4
JF
1373- (void) wb$updateFrame {
1374 CGRect frame([self frame]);
1375 frame.origin.y = 0;
1376
1377 for (UIView *view(self); ; ) {
1378 view = [view superview];
1379 if (view == nil)
1380 break;
1381 frame.origin.y -= [view frame].origin.y;
1382 }
1383
1384 [self setFrame:frame];
1385}
1386
98fe8d52
JF
1387@end
1388
a8d008e4
JF
1389MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1390 NSArray *subviews([self subviews]);
1391 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1392 if (view != nil && [view wb$isWBImageView])
1393 [view wb$updateFrame];
1394 _SBIconList$setFrame$(self, sel, frame);
1395}
1396
98fe8d52
JF
1397MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1398 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1399 NSArray *lists([_iconModel iconLists]);
1400
1401 for (unsigned i(0), e([lists count]); i != e; ++i)
1402 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]])) {
1403 SBIconList *list([lists objectAtIndex:i]);
1404 NSArray *subviews([list subviews]);
a8d008e4
JF
1405
1406 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1407 if (view == nil || ![view wb$isWBImageView]) {
1408 view = [[[WBImageView alloc] init] autorelease];
98fe8d52
JF
1409 [list insertSubview:view atIndex:0];
1410 }
a8d008e4 1411
98fe8d52 1412 UIImage *image([UIImage imageWithContentsOfFile:path]);
1a4ffdf8
JF
1413
1414 CGRect frame([view frame]);
1415 frame.size = [image size];
1416 [view setFrame:frame];
1417
98fe8d52 1418 [view setImage:image];
a8d008e4 1419 [view wb$updateFrame];
98fe8d52
JF
1420 }
1421
1422 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
95a5777b
JF
1423}
1424
e542b0ca
JF
1425MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1426 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
cf31d246
JF
1427 if (self != nil)
1428 [self setClipsToBounds:NO];
1429 return self;
1430}
1431
e542b0ca 1432MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
41165a1f
JF
1433 static bool gssc(false);
1434 if (!gssc) {
1435 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1436 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1437 gssc = true;
1438
1439 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1440 [Info_ setObject:[NSNumber numberWithBool:(
1441 !Papered_ ||
1442 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1443 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1444 )] forKey:@"UndockedIconLabels"];
1445 }
1446
2acbe5b8 1447 id &_label(MSHookIvar<id>(self, "_label"));
37351a17 1448 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
95a5777b 1449 docked = true;
e965c1e5 1450
2acbe5b8
JF
1451 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1452 [_label setInDock:docked];
e965c1e5
JF
1453
1454 _SBIconLabel$setInDock$(self, sel, docked);
1455 [self setNeedsDisplay];
889cb4f2
JF
1456}
1457
77d89d52
JF
1458MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1459 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1460}
1461
1462MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1463 _SBDockIconListView$setFrame$(self, sel, frame);
1464}
1465
e079e414
JF
1466// %hook -[NSBundle localizedStringForKey:value:table:] {{{
1467MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
4fa950df
JF
1468 NSString *identifier = [self bundleIdentifier];
1469 NSLocale *locale = [NSLocale currentLocale];
1470 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
2acbe5b8 1471 if (Debug_)
4fa950df
JF
1472 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1473 NSString *file = table == nil ? @"Localizable" : table;
1474 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1475 NSDictionary *strings;
1476 if ((strings = [Strings_ objectForKey:name]) != nil) {
1477 if (static_cast<id>(strings) != [NSNull null]) strings:
1478 if (NSString *value = [strings objectForKey:key])
1479 return value;
1480 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1481 language, file
1482 ], self, false)) {
1483 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1484 [Strings_ setObject:[strings autorelease] forKey:name];
1485 goto strings;
1486 } else goto null;
1487 } else null:
1488 [Strings_ setObject:[NSNull null] forKey:name];
e079e414 1489 return MSOldCall(key, value, table);
4fa950df 1490}
e079e414
JF
1491// }}}
1492// %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1493MSClassHook(WebCoreFrameBridge)
4fa950df 1494
e079e414 1495MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
7ff778ee
JF
1496 if (node == nil)
1497 return CGSizeZero;
1498 void **core(reinterpret_cast<void **>([node _node]));
1499 if (core == NULL || core[6] == NULL)
1500 return CGSizeZero;
e079e414 1501 return MSOldCall(node, width);
7ff778ee 1502}
e079e414 1503// }}}
7ff778ee 1504
b3f846db 1505MSInstanceMessage1(void, SBIconLabel, drawRect, CGRect, rect) {
cf31d246 1506 CGRect bounds = [self bounds];
e6f0817b 1507
a3fa54a5
JF
1508 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1509
aa6529f2 1510 int docked;
a3fa54a5
JF
1511 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1512 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
cf31d246 1513
6134e674 1514 NSString *label(MSHookIvar<NSString *>(self, "_label"));
cf31d246
JF
1515
1516 NSString *style = [NSString stringWithFormat:@""
1517 "font-family: Helvetica; "
1518 "font-weight: bold; "
ac1be56e 1519 "color: %@; %@"
1d3b613f 1520 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
ac1be56e
JF
1521 ? @"font-size: 12px; "
1522 : @"font-size: 11px; "
1523 )];
1524
1d3b613f 1525 if (IsWild_)
ac1be56e
JF
1526 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1527 else if (docked)
cf31d246 1528 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
d806256e
JF
1529
1530 bool ellipsis(false);
e6d5deb8 1531 float max = [self frame].size.width - 11, width;
d806256e
JF
1532 width:
1533 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
1534
1535 if (width > max) {
1536 size_t length([label length]);
1537 float spacing((width - max) / (length - 1));
1538
1539 if (spacing > 1.25) {
1540 ellipsis = true;
1541 label = [label substringToIndex:(length - 1)];
1542 goto width;
1543 }
1544
1545 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
1546 }
1547
1548 if (ellipsis)
1549 label = [label stringByAppendingString:@"..."];
1550
cf31d246
JF
1551 if (NSString *custom = [Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")])
1552 style = [style stringByAppendingString:custom];
1553
1554 CGSize size = [label sizeWithStyle:style forWidth:bounds.size.width];
1555 [label drawAtPoint:CGPointMake((bounds.size.width - size.width) / 2, 0) withStyle:style];
889cb4f2
JF
1556}
1557
b3f846db
JF
1558MSInstanceMessage0(CGImageRef, SBIconLabel, buildLabelImage) {
1559 bool docked((MSHookIvar<unsigned>(self, "_inDock") & 0x2) != 0);
1560
1561 WBStringDrawingState labelState = {NULL, 2, [NSString stringWithFormat:@""
1562 "color: %@;"
1563 ,
1564 (docked || !SummerBoard_ ? @"white" : @"#b3b3b3")
1565 ], docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1566
1567 stringDrawingState_ = &labelState;
1568
1569 CGImageRef image(MSOldCall());
1570
1571 stringDrawingState_ = NULL;
1572 return image;
1573}
1574
e079e414 1575// ChatKit {{{
6de35b7f
JF
1576MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1577 if ((self = MSOldCall(frame, delegate)) != nil) {
1578 [self setBackgroundColor:[UIColor clearColor]];
1579 } return self;
1580}
1581
1582MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1583 return SMSBackgrounded_ ? NO : MSOldCall();
1584}
1585
116c5704
JF
1586MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1587 [self wb$setBackgroundColor:[UIColor clearColor]];
1588 return MSOldCall();
1589}
1590
e079e414
JF
1591MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1592 MSOldCall(balloon);
198eb03b
JF
1593 [balloon setBackgroundColor:[UIColor clearColor]];
1594}
1595
e2435eef
JF
1596MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1597 MSOldCall([UIColor clearColor]);
096012f0 1598 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
e2435eef
JF
1599}
1600
05b58bf3 1601// iOS >= 5.0
a06fac53
JF
1602MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1603 if ((self = MSOldCall(style, reuse)) != nil) {
1604 [self setBackgroundColor:[UIColor clearColor]];
096012f0 1605 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
a06fac53
JF
1606 } return self;
1607}
1608
05b58bf3 1609// iOS << 5.0
e079e414
JF
1610MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1611 if ((self = MSOldCall(style, reuse)) != nil) {
bcb46132 1612 [self setBackgroundColor:[UIColor clearColor]];
198eb03b
JF
1613 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1614 } return self;
1615}
1616
e079e414
JF
1617MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1618 if ((self = MSOldCall(style, reuse)) != nil) {
198eb03b
JF
1619 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1620 [_label setBackgroundColor:[UIColor clearColor]];
1621 } return self;
1622}
1623
e079e414
JF
1624MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1625 MSOldCall(UITableViewCellSeparatorStyleNone);
198eb03b
JF
1626}
1627
e079e414
JF
1628MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1629 if ((self = MSOldCall(frame, style)) != nil) {
198eb03b
JF
1630 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1631 } return self;
1632}
1633
e079e414
JF
1634MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1635 MSOldCall();
e542b0ca 1636
d1c3b33f
JF
1637 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1638 if (UIImage *image = $getImage$(path)) {
6de35b7f
JF
1639 SMSBackgrounded_ = true;
1640
8b94f6b0 1641 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
4668cd8e 1642 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
8b94f6b0
JF
1643 UIView *table;
1644 if (&_transcriptTable != NULL)
1645 table = _transcriptTable;
1646 else if (&_transcriptLayer != NULL)
1647 table = _transcriptLayer;
1648 else
1649 table = nil;
1650
1651 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
4668cd8e 1652 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
8b94f6b0
JF
1653
1654 if (table == nil)
1655 [placard insertSubview:background atIndex:0];
1656 else {
1657 [table setBackgroundColor:[UIColor clearColor]];
1658 [placard insertSubview:background belowSubview:table];
1659 }
4668cd8e
JF
1660 }
1661}
e079e414 1662// }}}
4668cd8e 1663
e079e414 1664// %hook _UIImageWithName() {{{
4df9352e 1665MSHook(UIImage *, _UIImageWithName, NSString *name) {
95a5777b 1666 if (Debug_)
77d89d52 1667 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
2c2082b3
JF
1668 if (name == nil)
1669 return nil;
77d89d52
JF
1670
1671 int identifier;
1672 bool packed;
1673
1674 if (_UIPackedImageTableGetIdentifierForName != NULL)
1675 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1676 else if (_UISharedImageNameGetIdentifier != NULL) {
1677 identifier = _UISharedImageNameGetIdentifier(name);
1678 packed = identifier != -1;
1679 } else {
1680 identifier = -1;
1681 packed = false;
1682 }
1683
1684 if (Debug_)
1685 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
95a5777b 1686
77d89d52
JF
1687 if (!packed)
1688 return __UIImageWithName(name);
95a5777b 1689 else {
77d89d52
JF
1690 NSNumber *key([NSNumber numberWithInt:identifier]);
1691 UIImage *image([UIImages_ objectForKey:key]);
95a5777b 1692 if (image != nil)
77d89d52 1693 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
e10298ee
JF
1694 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1695 image = $getImage$(path);
95a5777b 1696 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
603984d9
JF
1697 if (image != nil)
1698 return image;
1699
1700 image = __UIImageWithName(name);
1701
1702 if (UIDebug_) {
1703 NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]);
1704 if (![Manager_ fileExistsAtPath:path])
1705 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
1706 }
1707
1708 return image;
95a5777b
JF
1709 }
1710}
e079e414
JF
1711// }}}
1712// %hook _UIImageWithNameInDomain() {{{
4df9352e 1713MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
96442a01
JF
1714 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1715 UIImage *image([PathImages_ objectForKey:key]);
e6f0817b 1716 if (image != nil)
96442a01 1717 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
95a5777b 1718 if (Debug_)
e6f0817b 1719 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
39271ad2 1720 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
e10298ee 1721 image = $getImage$(path);
e6f0817b 1722 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
96442a01 1723 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
95a5777b 1724}
e079e414 1725// }}}
95a5777b 1726
e079e414 1727// %hook GSFontCreateWithName() {{{
d806256e 1728MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
9c64bab2
JF
1729 if (Debug_)
1730 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
d806256e
JF
1731 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1732 name = [font UTF8String];
bae02419
JF
1733 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1734 // size *= [scale floatValue];
d806256e
JF
1735 return _GSFontCreateWithName(name, traits, size);
1736}
e079e414 1737// }}}
d806256e 1738
95a5777b
JF
1739#define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1740#define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1741
e542b0ca 1742bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
95a5777b 1743
e542b0ca 1744MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
9c64bab2
JF
1745 if (Debug_)
1746 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
e542b0ca 1747 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
95a5777b
JF
1748 if (Debug_)
1749 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1750
1751 if (value) {
1752 NSString *path = [NSString stringWithUTF8String:a1];
1753 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1754 NSString *file = [path substringFromIndex:31];
e079e414 1755 for (NSString *theme in Themes_) {
95a5777b
JF
1756 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1757 if ([Manager_ fileExistsAtPath:path]) {
1758 strcpy(a1, [path UTF8String]);
1759 continue;
1760 }
1761 }
1762 }
1763 }
1764 return value;
1765}
1766
1767static void ChangeWallpaper(
1768 CFNotificationCenterRef center,
1769 void *observer,
1770 CFStringRef name,
1771 const void *object,
1772 CFDictionaryRef info
1773) {
1774 if (Debug_)
1775 NSLog(@"WB:Debug:ChangeWallpaper!");
502d350e 1776
95a5777b 1777 UIImage *image;
4668cd8e 1778 if (WallpaperFile_ != nil) {
4df9352e 1779 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
95a5777b
JF
1780 if (image != nil)
1781 image = [image autorelease];
1782 } else image = nil;
502d350e
JF
1783
1784 if (WallpaperImage_ != nil)
1785 [WallpaperImage_ setImage:image];
1786 if (WallpaperPage_ != nil)
1787 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1788
95a5777b 1789}
394d1eb5 1790
0316ebc4
JF
1791#define WBRename(name, sel, imp) \
1792 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
e6f0817b 1793
e079e414
JF
1794template <typename Type_>
1795static void msset(Type_ &function, MSImageRef image, const char *name) {
1796 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1797}
1798
9c64bab2
JF
1799template <typename Type_>
1800static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1801 struct nlist &name(nl[index]);
1802 uintptr_t value(name.n_value);
1803 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1804 value |= 0x00000001;
1805 function = reinterpret_cast<Type_>(value);
1806}
1807
1808template <typename Type_>
1809static void dlset(Type_ &function, const char *name) {
8b94f6b0 1810 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
9c64bab2
JF
1811}
1812
e079e414
JF
1813// %hook CGImageReadCreateWithFile() {{{
1814MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1815 if (Debug_)
1816 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
265e19b2 1817 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
e079e414
JF
1818 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1819 [pool release];
1820 return value;
1821}
1822// }}}
d5168fd6 1823
32677d9d
JF
1824static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
1825 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1826 if (style == nil || [style length] == 0)
1827 style = @"font-family: Helvetica; font-size: 12px";
1828 return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
1829}
1830
1831static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
1832 if (style == nil || [style length] == 0)
1833 style = @"font-family: Helvetica; font-size: 12px";
1834 return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width];
1835}
1836
e079e414 1837static void SBInitialize() {
32677d9d
JF
1838 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
1839 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
394d1eb5 1840
e079e414
JF
1841 if (SummerBoard_) {
1842 WBRename(SBApplication, pathForIcon, pathForIcon);
1843 WBRename(SBApplicationIcon, icon, icon);
1844 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1845 }
81decb42 1846
e079e414
JF
1847 WBRename(SBBookmarkIcon, icon, icon);
1848 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1849 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1850 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1851 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
f64efe8d 1852
e079e414 1853 WBRename(SBWidgetApplicationIcon, icon, icon);
394d1eb5 1854
e079e414
JF
1855 WBRename(SBDockIconListView, setFrame:, setFrame$);
1856 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
f64efe8d 1857
b3f846db
JF
1858 if (kCFCoreFoundationVersionNumber < 600)
1859 WBRename(SBIconLabel, drawRect:, drawRect$);
1860 else
1861 WBRename(SBIconLabel, buildLabelImage, buildLabelImage);
1862
e079e414
JF
1863 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
1864 WBRename(SBIconLabel, setInDock:, setInDock$);
95a5777b 1865
e079e414 1866 WBRename(SBIconList, setFrame:, setFrame$);
d806256e 1867
e079e414
JF
1868 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
1869 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
1870 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
1871 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
2435118f 1872
e079e414
JF
1873 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
1874 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
1875 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
0316ebc4 1876
e079e414 1877 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
0316ebc4 1878
e079e414
JF
1879 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
1880 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
1881 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
1882 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
1883 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
1884 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
1885 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
1886 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
1887 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
0316ebc4 1888
e079e414
JF
1889 if (SummerBoard_)
1890 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
1891}
e6f0817b 1892
e079e414
JF
1893MSInitialize {
1894 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
e6f0817b 1895
e079e414
JF
1896 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
1897 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
e6f0817b 1898
502d350e 1899 Manager_ = [[NSFileManager defaultManager] retain];
e079e414 1900 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
502d350e 1901
e079e414 1902 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
26c43b47 1903
e079e414 1904 // Load Settings.plist {{{
265e19b2
JF
1905 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
1906 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
1907 SummerBoard_ = [value boolValue];
1908 if (NSNumber *value = [settings objectForKey:@"Debug"])
1909 Debug_ = [value boolValue];
8e699a82
JF
1910 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
1911 UIDebug_ = [value boolValue];
62b2dbad 1912
265e19b2 1913 NSArray *themes([settings objectForKey:@"Themes"]);
d5fb6e01
JF
1914 if (themes == nil)
1915 if (NSString *theme = [settings objectForKey:@"Theme"])
1916 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
1917 theme, @"Name",
95a5777b 1918 [NSNumber numberWithBool:true], @"Active",
d5fb6e01 1919 nil]];
265e19b2 1920
d5fb6e01
JF
1921 if (themes != nil)
1922 for (NSDictionary *theme in themes) {
265e19b2 1923 NSNumber *active([theme objectForKey:@"Active"]);
d5fb6e01
JF
1924 if (![active boolValue])
1925 continue;
26c43b47 1926
265e19b2 1927 NSString *name([theme objectForKey:@"Name"]);
d5fb6e01
JF
1928 if (name == nil)
1929 continue;
1930
265e19b2 1931 NSString *theme(nil);
d5fb6e01 1932
95a5777b
JF
1933 #define testForTheme(format...) \
1934 if (theme == nil) { \
1935 NSString *path = [NSString stringWithFormat:format]; \
1936 if ([Manager_ fileExistsAtPath:path]) { \
e079e414 1937 [Themes_ addObject:path]; \
95a5777b
JF
1938 continue; \
1939 } \
d5fb6e01 1940 }
d5fb6e01 1941
95a5777b
JF
1942 testForTheme(@"/Library/Themes/%@.theme", name)
1943 testForTheme(@"/Library/Themes/%@", name)
1944 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
265e19b2 1945
d5fb6e01 1946 }
26c43b47 1947 }
e079e414
JF
1948 // }}}
1949 // Merge Info.plist {{{
d5fb6e01
JF
1950 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1951
e079e414 1952 for (NSString *theme in Themes_)
265e19b2 1953 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
d5fb6e01
JF
1954 for (NSString *key in [info allKeys])
1955 if ([Info_ objectForKey:key] == nil)
1956 [Info_ setObject:[info objectForKey:key] forKey:key];
e079e414 1957 // }}}
95a5777b 1958
e079e414
JF
1959 // AudioToolbox {{{
1960 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
1961 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
1962 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
1963 }
1964 // }}}
1965 // GraphicsServices {{{
1966 if (true) {
1967 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
1968 }
1969 // }}}
1970 // ImageIO {{{
1971 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
1972 void *(*CGImageReadCreateWithFile)(NSString *, int);
1973 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
1974 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
1975 }
1976 // }}}
1977 // SpringBoard {{{
1978 if (SpringBoard_) {
39271ad2 1979 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
41165a1f 1980 Papered_ = $getTheme$(Wallpapers_) != nil;
5d46b7b0 1981 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
8b94f6b0 1982
95a5777b
JF
1983 CFNotificationCenterAddObserver(
1984 CFNotificationCenterGetDarwinNotifyCenter(),
1985 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
1986 );
62b2dbad 1987
cc46954c 1988 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
265e19b2
JF
1989 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
1990 if (MediaPlayer != nil)
1991 [MediaPlayer load];
1992
1993 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
1994 $MPVideoView = objc_getClass("MPVideoView");
cc46954c 1995 }
2acbe5b8 1996
e079e414 1997 SBInitialize();
2acbe5b8 1998 }
e079e414
JF
1999 // }}}
2000 // UIKit {{{
2001 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
2002 struct nlist nl[6];
2003 memset(nl, 0, sizeof(nl));
2004 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
2005 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
2006 nl[2].n_un.n_name = (char *) "__UIKitBundle";
2007 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
2008 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
2009 nlist(UIKit, nl);
2acbe5b8 2010
e079e414
JF
2011 nlset(_UIApplicationImageWithName, nl, 0);
2012 nlset(_UIImageWithNameInDomain, nl, 1);
2013 nlset(_UIKitBundle, nl, 2);
2014 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
2015 nlset(_UISharedImageNameGetIdentifier, nl, 4);
1d3b613f 2016
e079e414
JF
2017 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
2018 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
2019 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
2020 }
2021 // }}}
77d89d52 2022
8e699a82
JF
2023 if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) {
2024 NSError *error(nil);
2025 if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys:
2026 [NSNumber numberWithShort:0777], NSFilePosixPermissions,
2027 nil] error:&error])
2028 NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error);
2029 }
603984d9 2030
d5168fd6
JF
2031 [pool release];
2032}