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