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