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