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