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