]> git.saurik.com Git - winterboard.git/blame - Library.mm
Support SMSBackground@2x.
[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
57be87b3 652 [self drawAtPoint:point withStyle:style];
19fe3063
JF
653 return CGSizeZero;
654}
655
656MSInstanceMessageHook2(CGSize, NSString, drawAtPoint,withFont, CGPoint, point, UIFont *, font) {
657 if (stringDrawingState_ == NULL)
658 return MSOldCall(point, font);
659
660 NSString *style([[font markupDescription] stringByAppendingString:@";"]);
661
662 if (NSString *extra = stringDrawingState_->extra_)
663 style = [style stringByAppendingString:extra];
664
665 if (stringDrawingState_->key_ != nil)
666 if (NSString *extra = [Info_ objectForKey:stringDrawingState_->key_])
667 style = [style stringByAppendingString:extra];
668
669 stringDrawingState_ = stringDrawingState_->next_;
670
57be87b3 671 [self drawAtPoint:point withStyle:style];
19fe3063
JF
672 return CGSizeZero;
673}
674
675MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
676 WBStringDrawingState badgeState = {NULL, @""
677 "color: white;"
678 , @"BadgeStyle"};
679
680 stringDrawingState_ = &badgeState;
681
682 UIImage *image(MSOldCall(text));
683
684 stringDrawingState_ = NULL;
685 return image;
686}
687
688MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
689 WBStringDrawingState dayState = {NULL, @""
690 "color: white;"
691 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
692 , @"CalendarIconDayStyle"};
693
694 WBStringDrawingState dateState = {&dayState, @""
695 "color: #333333;"
696 , @"CalendarIconDateStyle"};
697
698 stringDrawingState_ = &dateState;
699
700 UIImage *image(MSOldCall(type));
701
702 stringDrawingState_ = NULL;
703 return image;
704}
705
0316ebc4 706MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
4668cd8e
JF
707 NSBundle *bundle([NSBundle mainBundle]);
708
e6f0817b
JF
709 CFLocaleRef locale(CFLocaleCopyCurrent());
710 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
711 CFRelease(locale);
712
713 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
714
77d89d52 715 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
e6f0817b 716 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
44aa4549 717 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
e6f0817b
JF
718 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
719
720 CFRelease(now);
721
722 CFRelease(formatter);
723
c79980f5 724 NSString *datestyle([@""
e6f0817b
JF
725 "font-family: Helvetica; "
726 "font-weight: bold; "
e6f0817b
JF
727 "color: #333333; "
728 "alpha: 1.0; "
1d3b613f 729 "" stringByAppendingString:(IsWild_
c79980f5
JF
730 ? @"font-size: 54px; "
731 : @"font-size: 39px; "
732 )]);
e6f0817b 733
c79980f5 734 NSString *daystyle([@""
e6f0817b
JF
735 "font-family: Helvetica; "
736 "font-weight: bold; "
e6f0817b
JF
737 "color: white; "
738 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
1d3b613f 739 "" stringByAppendingString:(IsWild_
c79980f5
JF
740 ? @"font-size: 11px; "
741 : @"font-size: 9px; "
742 )]);
e6f0817b
JF
743
744 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
745 datestyle = [datestyle stringByAppendingString:style];
746 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
747 daystyle = [daystyle stringByAppendingString:style];
748
cf31d246 749 float width([self bounds].size.width);
4668cd8e
JF
750 float leeway(10);
751 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
752 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
e6f0817b 753
77d89d52 754 unsigned base0(IsWild_ ? 89 : 70);
c79980f5 755 if ($GSFontGetUseLegacyFontMetrics())
77d89d52
JF
756 base0 = base0 + 1;
757 unsigned base1(IsWild_ ? 18 : 16);
758
759 if (Four_) {
760 ++base0;
761 ++base1;
762 }
81decb42 763
e6f0817b 764 [(NSString *)date drawAtPoint:CGPointMake(
77d89d52 765 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
e6f0817b
JF
766 ) withStyle:datestyle];
767
768 [(NSString *)day drawAtPoint:CGPointMake(
77d89d52 769 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
e6f0817b
JF
770 ) withStyle:daystyle];
771
772 CFRelease(date);
773 CFRelease(day);
774}
775
e079e414
JF
776// %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
777void $setBarStyle$_(NSString *name, int &style) {
778 if (Debug_)
779 NSLog(@"WB:Debug:%@Style:%d", name, style);
780 NSNumber *number = nil;
781 if (number == nil)
782 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
783 if (number == nil)
784 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
785 if (number != nil) {
d5fb6e01 786 style = [number intValue];
e079e414
JF
787 if (Debug_)
788 NSLog(@"WB:Debug:%@Style=%d", name, style);
789 }
26c43b47
JF
790}
791
e079e414 792MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
0316ebc4 793 $setBarStyle$_(@"Toolbar", style);
e079e414 794 return MSOldCall(style);
95a5777b
JF
795}
796
e079e414 797MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
0316ebc4 798 $setBarStyle$_(@"NavigationBar", style);
e079e414 799 return MSOldCall(style);
26c43b47 800}
e079e414 801// }}}
26c43b47 802
0316ebc4 803MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
2acbe5b8 804 [[self superview] setBackgroundColor:[UIColor clearColor]];
0316ebc4 805 _SBButtonBar$didMoveToSuperview(self, sel);
08454e3a 806}
62b2dbad 807
0316ebc4
JF
808MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
809 [[self superview] setBackgroundColor:[UIColor clearColor]];
810 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
811}
812
813MSHook(UIImage *, UIImage$defaultDesktopImage, UIImage *self, SEL sel) {
502d350e
JF
814 if (Debug_)
815 NSLog(@"WB:Debug:DefaultDesktopImage");
816 if (NSString *path = $getTheme$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil]))
2acbe5b8 817 return [UIImage imageWithContentsOfFile:path];
0316ebc4 818 return _UIImage$defaultDesktopImage(self, sel);
502d350e
JF
819}
820
4668cd8e 821static NSArray *Wallpapers_;
1d3b613f 822static bool Papered_;
77d89d52 823static bool Docked_;
4668cd8e 824static NSString *WallpaperFile_;
502d350e
JF
825static UIImageView *WallpaperImage_;
826static UIWebDocumentView *WallpaperPage_;
827static NSURL *WallpaperURL_;
95a5777b 828
4668cd8e
JF
829#define _release(object) \
830 do if (object != nil) { \
831 [object release]; \
832 object = nil; \
833 } while (false)
834
e079e414 835static UIImage *$getImage$(NSString *path) {
e079e414
JF
836 UIImage *image([UIImage imageWithContentsOfFile:path]);
837
5b21732c 838 unsigned scale($getScale$(path));
e079e414
JF
839 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
840 [image setScale:scale];
841
842 return image;
843}
844
845// %hook -[SBUIController init] {{{
846MSInstanceMessageHook0(id, SBUIController, init) {
847 self = MSOldCall();
d5168fd6
JF
848 if (self == nil)
849 return nil;
850
39271ad2 851 NSString *paper($getTheme$(Wallpapers_));
ecf154db
JF
852 if (paper != nil)
853 paper = [paper stringByDeletingLastPathComponent];
e079e414 854
609e1cd8
JF
855 {
856 size_t size;
857 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
858 char *machine = new char[size];
859
860 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
861 perror("sysctlbyname(\"hw.machine\", ?)");
862 delete [] machine;
863 machine = NULL;
864 }
865
866 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
867 }
226d2af9 868
3135f5ed
JF
869 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
870
0137e6de
JF
871 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
872 [Info_ setObject:[NSNumber numberWithBool:(
e079e414 873 !(paper != nil || GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"))) ||
0137e6de
JF
874 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
875 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
876 )] forKey:@"UndockedIconLabels"];
877
878 if (Debug_)
879 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
880
e079e414 881 if (paper != nil) {
55e82d74 882 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
1d3b613f
JF
883 if (&_wallpaperView != NULL) {
884 [_wallpaperView removeFromSuperview];
885 [_wallpaperView release];
886 _wallpaperView = nil;
887 }
888 }
889
44aa4549 890 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
69550bfb
JF
891 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
892
77d89d52 893 UIView **player;
44aa4549 894 if (&_contentLayer != NULL)
77d89d52 895 player = &_contentLayer;
44aa4549 896 else if (&_contentView != NULL)
77d89d52 897 player = &_contentView;
44aa4549 898 else
77d89d52 899 player = NULL;
77d89d52 900 UIView *layer(player == NULL ? nil : *player);
44aa4549 901
55e82d74
JF
902 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
903 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
904 [window setContentView:content];
905
906 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
907 [window setBackgroundColor:[_window backgroundColor]];
908 [_window setBackgroundColor:[UIColor clearColor]];
909
910 [window setLevel:-1000];
911 [window setHidden:NO];
1d3b613f 912
77d89d52
JF
913 /*if (player != NULL)
914 *player = content;*/
915
44aa4549
JF
916 [content setBackgroundColor:[layer backgroundColor]];
917 [layer setBackgroundColor:[UIColor clearColor]];
69550bfb 918
1d3b613f
JF
919 UIView *indirect;
920 if (!SummerBoard_ || !IsWild_)
921 indirect = content;
922 else {
923 CGRect bounds([content bounds]);
c8fbf228 924 bounds.origin.y = -30;
1d3b613f
JF
925 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
926 [content addSubview:indirect];
927 [indirect zoomToScale:2.4];
928 }
929
4668cd8e
JF
930 _release(WallpaperFile_);
931 _release(WallpaperImage_);
932 _release(WallpaperPage_);
933 _release(WallpaperURL_);
934
ecf154db
JF
935 if (paper != nil) {
936 NSArray *themes([NSArray arrayWithObject:paper]);
937
938 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
d806256e
JF
939#if UseAVController
940 NSError *error;
941
942 static AVController *controller_(nil);
943 if (controller_ == nil) {
944 AVQueue *queue([AVQueue avQueue]);
945 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
946 }
947
948 AVQueue *queue([controller_ queue]);
949
1d3b613f 950 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
d806256e
JF
951 [controller_ setLayer:[video _layer]];
952
e079e414 953 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
d806256e
JF
954 [queue appendItem:item error:&error];
955
956 [controller_ play:&error];
957#elif UseMPMoviePlayerController
e079e414 958 NSURL *url([NSURL fileURLWithPath:path]);
265e19b2 959 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
d806256e
JF
960 controller.movieControlMode = MPMovieControlModeHidden;
961 [controller play];
962#else
1d3b613f 963 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
e079e414 964 [video setMovieWithPath:path];
4668cd8e 965 [video setRepeatMode:1];
d806256e 966 [video setRepeatGap:-1];
4668cd8e 967 [video playFromBeginning];;
d806256e
JF
968#endif
969
1d3b613f 970 [indirect addSubview:video];
4668cd8e 971 }
d5fb6e01 972
b461e3ec 973 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
e079e414
JF
974 if (UIImage *image = $getImage$(path)) {
975 WallpaperFile_ = [path retain];
976 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
977 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
978 [WallpaperImage_ setAlpha:[number floatValue]];
979 [indirect addSubview:WallpaperImage_];
980 }
4668cd8e 981 }
394d1eb5 982
b461e3ec 983 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1d3b613f 984 CGRect bounds = [indirect bounds];
502d350e 985
4668cd8e
JF
986 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
987 [view setAutoresizes:true];
502d350e 988
4668cd8e 989 WallpaperPage_ = [view retain];
e079e414 990 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
394d1eb5 991
4668cd8e
JF
992 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
993
4668cd8e 994 [view setBackgroundColor:[UIColor clearColor]];
1a4ffdf8
JF
995 if ([view respondsToSelector:@selector(setDrawsBackground:)])
996 [view setDrawsBackground:NO];
997 [[view webView] setDrawsBackground:NO];
394d1eb5 998
1d3b613f 999 [indirect addSubview:view];
4668cd8e 1000 }
08454e3a 1001 }
d5168fd6 1002
e079e414
JF
1003 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1004 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
5e5c7190
JF
1005 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1006 if ([Manager_ fileExistsAtPath:html]) {
1d3b613f 1007 CGRect bounds = [indirect bounds];
5e5c7190
JF
1008
1009 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
1010 [view setAutoresizes:true];
1011
1012 NSURL *url = [NSURL fileURLWithPath:html];
1013 [view loadRequest:[NSURLRequest requestWithURL:url]];
1014
5e5c7190 1015 [view setBackgroundColor:[UIColor clearColor]];
1a4ffdf8
JF
1016 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1017 [view setDrawsBackground:NO];
1018 [[view webView] setDrawsBackground:NO];
5e5c7190 1019
1d3b613f 1020 [indirect addSubview:view];
5e5c7190
JF
1021 }
1022 }
1023
d5168fd6
JF
1024 return self;
1025}
e079e414 1026// }}}
d5168fd6 1027
9cfe3924 1028MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
502d350e 1029 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
2acbe5b8 1030 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
502d350e 1031
2acbe5b8
JF
1032 if (path != nil && _backgroundView != nil)
1033 path = nil;
502d350e 1034
9cfe3924 1035 _SBAwayView$updateDesktopImage$(self, sel, image);
502d350e
JF
1036
1037 if (path != nil) {
1038 CGRect bounds = [self bounds];
1039
2acbe5b8 1040 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
502d350e
JF
1041 [view setAutoresizes:true];
1042
1043 if (WallpaperPage_ != nil)
1044 [WallpaperPage_ release];
1045 WallpaperPage_ = [view retain];
1046
1047 if (WallpaperURL_ != nil)
1048 [WallpaperURL_ release];
1049 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1050
1051 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1052
1053 [[view webView] setDrawsBackground:false];
2acbe5b8 1054 [view setBackgroundColor:[UIColor clearColor]];
502d350e 1055
2acbe5b8 1056 [self insertSubview:view aboveSubview:_backgroundView];
ca13798d 1057 }
502d350e 1058}
ca13798d 1059
95a5777b 1060/*extern "C" CGColorRef CGGStateGetSystemColor(void *);
ca13798d
JF
1061extern "C" CGColorRef CGGStateGetFillColor(void *);
1062extern "C" CGColorRef CGGStateGetStrokeColor(void *);
95a5777b 1063extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
ca13798d 1064
cd6ad593
JF
1065/* WBTimeLabel {{{ */
1066@interface WBTimeLabel : NSProxy {
ca13798d
JF
1067 NSString *time_;
1068 _transient SBStatusBarTimeView *view_;
889cb4f2
JF
1069}
1070
ca13798d 1071- (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
889cb4f2
JF
1072
1073@end
1074
cd6ad593 1075@implementation WBTimeLabel
889cb4f2
JF
1076
1077- (void) dealloc {
ca13798d 1078 [time_ release];
889cb4f2
JF
1079 [super dealloc];
1080}
1081
ca13798d
JF
1082- (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1083 time_ = [time retain];
1084 view_ = view;
889cb4f2
JF
1085 return self;
1086}
1087
44aa4549
JF
1088- (NSString *) description {
1089 return time_;
1090}
1091
ca13798d
JF
1092WBDelegate(time_)
1093
1094- (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
d5fb6e01 1095 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
2acbe5b8 1096 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
d5fb6e01
JF
1097
1098 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1099 "font-family: Helvetica; "
1100 "font-weight: bold; "
1101 "font-size: 14px; "
1102 "color: %@; "
2acbe5b8 1103 "%@", _mode ? @"white" : @"black", custom]];
d5fb6e01
JF
1104
1105 return CGSizeZero;
1106 }
ca13798d
JF
1107
1108 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
889cb4f2
JF
1109}
1110
cd6ad593
JF
1111@end
1112/* }}} */
1113/* WBBadgeLabel {{{ */
1114@interface WBBadgeLabel : NSProxy {
1115 NSString *badge_;
1116}
1117
1118- (id) initWithBadge:(NSString *)badge;
29155933 1119- (NSString *) description;
cd6ad593 1120
ca13798d
JF
1121@end
1122
cd6ad593
JF
1123@implementation WBBadgeLabel
1124
1125- (void) dealloc {
1126 [badge_ release];
1127 [super dealloc];
889cb4f2
JF
1128}
1129
cd6ad593
JF
1130- (id) initWithBadge:(NSString *)badge {
1131 badge_ = [badge retain];
1132 return self;
1133}
1134
29155933
JF
1135- (NSString *) description {
1136 return [badge_ description];
1137}
1138
cd6ad593
JF
1139WBDelegate(badge_)
1140
1141- (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
1142 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1143 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1144 "font-family: Helvetica; "
1145 "font-weight: bold; "
1146 "font-size: 17px; "
1147 "color: white; "
1148 "%@", custom]];
1149
1150 return CGSizeZero;
1151 }
1152
1153 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1154}
ca13798d
JF
1155
1156@end
cd6ad593
JF
1157/* }}} */
1158
e079e414
JF
1159// IconAlpha {{{
1160MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, float, alpha) {
8e4d2f42
JF
1161 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1162 alpha = [number floatValue];
e079e414 1163 return MSOldCall(alpha);
8e4d2f42
JF
1164}
1165
e079e414 1166MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, float, alpha) {
8e4d2f42
JF
1167 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1168 alpha = [number floatValue];
e079e414 1169 return MSOldCall(alpha);
8e4d2f42
JF
1170}
1171
e079e414
JF
1172MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1173 if ((self = MSOldCall()) != nil) {
8e4d2f42
JF
1174 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1175 // XXX: note: this is overridden above, which is silly
1176 float alpha([number floatValue]);
1177 [self setIconImageAlpha:alpha];
1178 [self setIconLabelAlpha:alpha];
1179 }
1180 } return self;
1181}
1182
e079e414 1183MSInstanceMessageHook1(void, SBIcon, setAlpha, float, alpha) {
b0d0c73f
JF
1184 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1185 alpha = [number floatValue];
e079e414 1186 return MSOldCall(alpha);
b0d0c73f 1187}
e079e414 1188// }}}
b0d0c73f 1189
0316ebc4
JF
1190MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1191 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
2acbe5b8
JF
1192 id &_badge(MSHookIvar<id>(self, "_badge"));
1193 if (_badge != nil)
1194 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1195 _badge = label;
cd6ad593
JF
1196 } return self;
1197}
ca13798d 1198
69550bfb 1199void SBStatusBarController$setStatusBarMode(int &mode) {
95a5777b
JF
1200 if (Debug_)
1201 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
502d350e 1202 if (mode < 100) // 104:hidden 105:glowing
95a5777b
JF
1203 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1204 mode = [number intValue];
d5fb6e01
JF
1205}
1206
69550bfb
JF
1207/*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1208 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1209 SBStatusBarController$setStatusBarMode(mode);
1210 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1211}*/
1212
1213MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
8b94f6b0 1214 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
69550bfb
JF
1215 SBStatusBarController$setStatusBarMode(mode);
1216 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1217}
1218
1219MSHook(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 1220 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
69550bfb 1221 SBStatusBarController$setStatusBarMode(mode);
8b94f6b0 1222 //NSLog(@"mode=%u", mode);
69550bfb
JF
1223 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1224}
1225
1226/*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
d5fb6e01
JF
1227 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1228 mode = [number intValue];
0316ebc4 1229 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
69550bfb 1230}*/
d5fb6e01 1231
0316ebc4
JF
1232MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1233 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
4668cd8e
JF
1234 if (Debug_)
1235 NSLog(@"operatorNameStyle= %@", style);
1236 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1237 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1238 return style;
1239}
1240
0316ebc4 1241MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
4668cd8e
JF
1242 if (Debug_)
1243 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
0316ebc4 1244 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
4668cd8e
JF
1245}
1246
0316ebc4
JF
1247// XXX: replace this with [SBStatusBarTimeView tile]
1248MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
2acbe5b8
JF
1249 id &_time(MSHookIvar<id>(self, "_time"));
1250 if (_time != nil && [_time class] != [WBTimeLabel class])
1251 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
0316ebc4 1252 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
ca13798d
JF
1253}
1254
98fe8d52 1255@interface UIView (WinterBoard)
a8d008e4 1256- (bool) wb$isWBImageView;
198eb03b 1257- (void) wb$logHierarchy;
98fe8d52
JF
1258@end
1259
1260@implementation UIView (WinterBoard)
1261
a8d008e4 1262- (bool) wb$isWBImageView {
98fe8d52
JF
1263 return false;
1264}
1265
198eb03b
JF
1266- (void) wb$logHierarchy {
1267 WBLogHierarchy(self);
1268}
1269
98fe8d52
JF
1270@end
1271
a8d008e4
JF
1272@interface WBImageView : UIImageView {
1273}
1274
1275- (bool) wb$isWBImageView;
1276- (void) wb$updateFrame;
98fe8d52
JF
1277@end
1278
a8d008e4 1279@implementation WBImageView
98fe8d52 1280
a8d008e4 1281- (bool) wb$isWBImageView {
98fe8d52
JF
1282 return true;
1283}
1284
a8d008e4
JF
1285- (void) wb$updateFrame {
1286 CGRect frame([self frame]);
1287 frame.origin.y = 0;
1288
1289 for (UIView *view(self); ; ) {
1290 view = [view superview];
1291 if (view == nil)
1292 break;
1293 frame.origin.y -= [view frame].origin.y;
1294 }
1295
1296 [self setFrame:frame];
1297}
1298
98fe8d52
JF
1299@end
1300
a8d008e4
JF
1301MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1302 NSArray *subviews([self subviews]);
1303 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1304 if (view != nil && [view wb$isWBImageView])
1305 [view wb$updateFrame];
1306 _SBIconList$setFrame$(self, sel, frame);
1307}
1308
98fe8d52
JF
1309MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1310 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1311 NSArray *lists([_iconModel iconLists]);
1312
1313 for (unsigned i(0), e([lists count]); i != e; ++i)
1314 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]])) {
1315 SBIconList *list([lists objectAtIndex:i]);
1316 NSArray *subviews([list subviews]);
a8d008e4
JF
1317
1318 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1319 if (view == nil || ![view wb$isWBImageView]) {
1320 view = [[[WBImageView alloc] init] autorelease];
98fe8d52
JF
1321 [list insertSubview:view atIndex:0];
1322 }
a8d008e4 1323
98fe8d52 1324 UIImage *image([UIImage imageWithContentsOfFile:path]);
1a4ffdf8
JF
1325
1326 CGRect frame([view frame]);
1327 frame.size = [image size];
1328 [view setFrame:frame];
1329
98fe8d52 1330 [view setImage:image];
a8d008e4 1331 [view wb$updateFrame];
98fe8d52
JF
1332 }
1333
1334 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
95a5777b
JF
1335}
1336
e542b0ca
JF
1337MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1338 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
cf31d246
JF
1339 if (self != nil)
1340 [self setClipsToBounds:NO];
1341 return self;
1342}
1343
e542b0ca 1344MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
2acbe5b8 1345 id &_label(MSHookIvar<id>(self, "_label"));
37351a17 1346 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
95a5777b 1347 docked = true;
2acbe5b8
JF
1348 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1349 [_label setInDock:docked];
e542b0ca 1350 return _SBIconLabel$setInDock$(self, sel, docked);
889cb4f2
JF
1351}
1352
77d89d52
JF
1353MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1354 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1355}
1356
1357MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1358 _SBDockIconListView$setFrame$(self, sel, frame);
1359}
1360
e079e414
JF
1361// %hook -[NSBundle localizedStringForKey:value:table:] {{{
1362MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
4fa950df
JF
1363 NSString *identifier = [self bundleIdentifier];
1364 NSLocale *locale = [NSLocale currentLocale];
1365 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
2acbe5b8 1366 if (Debug_)
4fa950df
JF
1367 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1368 NSString *file = table == nil ? @"Localizable" : table;
1369 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1370 NSDictionary *strings;
1371 if ((strings = [Strings_ objectForKey:name]) != nil) {
1372 if (static_cast<id>(strings) != [NSNull null]) strings:
1373 if (NSString *value = [strings objectForKey:key])
1374 return value;
1375 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1376 language, file
1377 ], self, false)) {
1378 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1379 [Strings_ setObject:[strings autorelease] forKey:name];
1380 goto strings;
1381 } else goto null;
1382 } else null:
1383 [Strings_ setObject:[NSNull null] forKey:name];
e079e414 1384 return MSOldCall(key, value, table);
4fa950df 1385}
e079e414
JF
1386// }}}
1387// %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1388MSClassHook(WebCoreFrameBridge)
4fa950df 1389
e079e414 1390MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
7ff778ee
JF
1391 if (node == nil)
1392 return CGSizeZero;
1393 void **core(reinterpret_cast<void **>([node _node]));
1394 if (core == NULL || core[6] == NULL)
1395 return CGSizeZero;
e079e414 1396 return MSOldCall(node, width);
7ff778ee 1397}
e079e414 1398// }}}
7ff778ee 1399
32677d9d 1400MSInstanceMessageHook1(void, SBIconLabel, drawRect, CGRect, rect) {
cf31d246 1401 CGRect bounds = [self bounds];
e6f0817b 1402
a3fa54a5
JF
1403 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1404
aa6529f2 1405 int docked;
a3fa54a5
JF
1406 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1407 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
cf31d246 1408
6134e674 1409 NSString *label(MSHookIvar<NSString *>(self, "_label"));
cf31d246
JF
1410
1411 NSString *style = [NSString stringWithFormat:@""
1412 "font-family: Helvetica; "
1413 "font-weight: bold; "
ac1be56e 1414 "color: %@; %@"
1d3b613f 1415 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
ac1be56e
JF
1416 ? @"font-size: 12px; "
1417 : @"font-size: 11px; "
1418 )];
1419
1d3b613f 1420 if (IsWild_)
ac1be56e
JF
1421 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1422 else if (docked)
cf31d246 1423 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
d806256e
JF
1424
1425 bool ellipsis(false);
1426 float max = 75, width;
1427 width:
1428 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
1429
1430 if (width > max) {
1431 size_t length([label length]);
1432 float spacing((width - max) / (length - 1));
1433
1434 if (spacing > 1.25) {
1435 ellipsis = true;
1436 label = [label substringToIndex:(length - 1)];
1437 goto width;
1438 }
1439
1440 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
1441 }
1442
1443 if (ellipsis)
1444 label = [label stringByAppendingString:@"..."];
1445
cf31d246
JF
1446 if (NSString *custom = [Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")])
1447 style = [style stringByAppendingString:custom];
1448
1449 CGSize size = [label sizeWithStyle:style forWidth:bounds.size.width];
1450 [label drawAtPoint:CGPointMake((bounds.size.width - size.width) / 2, 0) withStyle:style];
889cb4f2
JF
1451}
1452
e079e414
JF
1453// ChatKit {{{
1454MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1455 MSOldCall(balloon);
198eb03b
JF
1456 [balloon setBackgroundColor:[UIColor clearColor]];
1457}
1458
e079e414
JF
1459MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1460 if ((self = MSOldCall(style, reuse)) != nil) {
198eb03b
JF
1461 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1462 } return self;
1463}
1464
e079e414
JF
1465MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1466 if ((self = MSOldCall(style, reuse)) != nil) {
198eb03b
JF
1467 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
1468 [_label setBackgroundColor:[UIColor clearColor]];
1469 } return self;
1470}
1471
e079e414
JF
1472MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
1473 MSOldCall(UITableViewCellSeparatorStyleNone);
198eb03b
JF
1474}
1475
e079e414
JF
1476MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
1477 if ((self = MSOldCall(frame, style)) != nil) {
198eb03b
JF
1478 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
1479 } return self;
1480}
1481
e079e414
JF
1482MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
1483 MSOldCall();
e542b0ca 1484
d1c3b33f
JF
1485 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
1486 if (UIImage *image = $getImage$(path)) {
8b94f6b0 1487 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
4668cd8e 1488 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
8b94f6b0
JF
1489 UIView *table;
1490 if (&_transcriptTable != NULL)
1491 table = _transcriptTable;
1492 else if (&_transcriptLayer != NULL)
1493 table = _transcriptLayer;
1494 else
1495 table = nil;
1496
1497 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
4668cd8e 1498 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
8b94f6b0
JF
1499
1500 if (table == nil)
1501 [placard insertSubview:background atIndex:0];
1502 else {
1503 [table setBackgroundColor:[UIColor clearColor]];
1504 [placard insertSubview:background belowSubview:table];
1505 }
4668cd8e
JF
1506 }
1507}
e079e414 1508// }}}
4668cd8e 1509
e079e414 1510// %hook _UIImageWithName() {{{
4df9352e 1511MSHook(UIImage *, _UIImageWithName, NSString *name) {
95a5777b 1512 if (Debug_)
77d89d52 1513 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
2c2082b3
JF
1514 if (name == nil)
1515 return nil;
77d89d52
JF
1516
1517 int identifier;
1518 bool packed;
1519
1520 if (_UIPackedImageTableGetIdentifierForName != NULL)
1521 packed = _UIPackedImageTableGetIdentifierForName(name, &identifier);
1522 else if (_UISharedImageNameGetIdentifier != NULL) {
1523 identifier = _UISharedImageNameGetIdentifier(name);
1524 packed = identifier != -1;
1525 } else {
1526 identifier = -1;
1527 packed = false;
1528 }
1529
1530 if (Debug_)
1531 NSLog(@"WB:Debug: _UISharedImageNameGetIdentifier(\"%@\") = %d", name, identifier);
95a5777b 1532
77d89d52
JF
1533 if (!packed)
1534 return __UIImageWithName(name);
95a5777b 1535 else {
77d89d52
JF
1536 NSNumber *key([NSNumber numberWithInt:identifier]);
1537 UIImage *image([UIImages_ objectForKey:key]);
95a5777b 1538 if (image != nil)
77d89d52 1539 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithName(name) : image;
e10298ee
JF
1540 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true))
1541 image = $getImage$(path);
95a5777b 1542 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
77d89d52 1543 return image == nil ? __UIImageWithName(name) : image;
95a5777b
JF
1544 }
1545}
e079e414
JF
1546// }}}
1547// %hook _UIImageWithNameInDomain() {{{
4df9352e 1548MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
96442a01
JF
1549 NSString *key([NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]);
1550 UIImage *image([PathImages_ objectForKey:key]);
e6f0817b 1551 if (image != nil)
96442a01 1552 return reinterpret_cast<id>(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image;
95a5777b 1553 if (Debug_)
e6f0817b 1554 NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
39271ad2 1555 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])))
e10298ee 1556 image = $getImage$(path);
e6f0817b 1557 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
96442a01 1558 return image == nil ? __UIImageWithNameInDomain(name, domain) : image;
95a5777b 1559}
e079e414 1560// }}}
95a5777b 1561
e079e414 1562// %hook GSFontCreateWithName() {{{
d806256e 1563MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
9c64bab2
JF
1564 if (Debug_)
1565 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
d806256e
JF
1566 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
1567 name = [font UTF8String];
bae02419
JF
1568 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
1569 // size *= [scale floatValue];
d806256e
JF
1570 return _GSFontCreateWithName(name, traits, size);
1571}
e079e414 1572// }}}
d806256e 1573
95a5777b
JF
1574#define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
1575#define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
1576
e542b0ca 1577bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long a0, char *a1, bool &a2);
95a5777b 1578
e542b0ca 1579MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a2) {
9c64bab2
JF
1580 if (Debug_)
1581 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %p, %u)", a0, a1, a2);
e542b0ca 1582 bool value = __Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
95a5777b
JF
1583 if (Debug_)
1584 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
1585
1586 if (value) {
1587 NSString *path = [NSString stringWithUTF8String:a1];
1588 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
1589 NSString *file = [path substringFromIndex:31];
e079e414 1590 for (NSString *theme in Themes_) {
95a5777b
JF
1591 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
1592 if ([Manager_ fileExistsAtPath:path]) {
1593 strcpy(a1, [path UTF8String]);
1594 continue;
1595 }
1596 }
1597 }
1598 }
1599 return value;
1600}
1601
1602static void ChangeWallpaper(
1603 CFNotificationCenterRef center,
1604 void *observer,
1605 CFStringRef name,
1606 const void *object,
1607 CFDictionaryRef info
1608) {
1609 if (Debug_)
1610 NSLog(@"WB:Debug:ChangeWallpaper!");
502d350e 1611
95a5777b 1612 UIImage *image;
4668cd8e 1613 if (WallpaperFile_ != nil) {
4df9352e 1614 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
95a5777b
JF
1615 if (image != nil)
1616 image = [image autorelease];
1617 } else image = nil;
502d350e
JF
1618
1619 if (WallpaperImage_ != nil)
1620 [WallpaperImage_ setImage:image];
1621 if (WallpaperPage_ != nil)
1622 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1623
95a5777b 1624}
394d1eb5 1625
0316ebc4
JF
1626#define WBRename(name, sel, imp) \
1627 _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp)
e6f0817b 1628
e079e414
JF
1629template <typename Type_>
1630static void msset(Type_ &function, MSImageRef image, const char *name) {
1631 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
1632}
1633
9c64bab2
JF
1634template <typename Type_>
1635static void nlset(Type_ &function, struct nlist *nl, size_t index) {
1636 struct nlist &name(nl[index]);
1637 uintptr_t value(name.n_value);
1638 if ((name.n_desc & N_ARM_THUMB_DEF) != 0)
1639 value |= 0x00000001;
1640 function = reinterpret_cast<Type_>(value);
1641}
1642
1643template <typename Type_>
1644static void dlset(Type_ &function, const char *name) {
8b94f6b0 1645 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
9c64bab2
JF
1646}
1647
e079e414
JF
1648// %hook CGImageReadCreateWithFile() {{{
1649MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
1650 if (Debug_)
1651 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
265e19b2 1652 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
e079e414
JF
1653 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
1654 [pool release];
1655 return value;
1656}
1657// }}}
d5168fd6 1658
32677d9d
JF
1659static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
1660 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
1661 if (style == nil || [style length] == 0)
1662 style = @"font-family: Helvetica; font-size: 12px";
1663 return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
1664}
1665
1666static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) {
1667 if (style == nil || [style length] == 0)
1668 style = @"font-family: Helvetica; font-size: 12px";
1669 return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width];
1670}
1671
e079e414 1672static void SBInitialize() {
32677d9d
JF
1673 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
1674 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
394d1eb5 1675
32677d9d 1676 _UIImage$defaultDesktopImage = MSHookMessage(object_getClass($UIImage), @selector(defaultDesktopImage), &$UIImage$defaultDesktopImage);
95a5777b 1677
e079e414
JF
1678 if (SummerBoard_) {
1679 WBRename(SBApplication, pathForIcon, pathForIcon);
1680 WBRename(SBApplicationIcon, icon, icon);
1681 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
1682 }
81decb42 1683
e079e414
JF
1684 WBRename(SBBookmarkIcon, icon, icon);
1685 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
1686 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
1687 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
1688 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
f64efe8d 1689
e079e414 1690 WBRename(SBWidgetApplicationIcon, icon, icon);
394d1eb5 1691
e079e414
JF
1692 WBRename(SBDockIconListView, setFrame:, setFrame$);
1693 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
f64efe8d 1694
e079e414
JF
1695 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
1696 WBRename(SBIconLabel, setInDock:, setInDock$);
95a5777b 1697
e079e414 1698 WBRename(SBIconList, setFrame:, setFrame$);
d806256e 1699
e079e414
JF
1700 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
1701 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
1702 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
1703 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
2435118f 1704
e079e414
JF
1705 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
1706 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
1707 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
0316ebc4 1708
e079e414 1709 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
0316ebc4 1710
e079e414
JF
1711 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
1712 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
1713 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
1714 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
1715 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
1716 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
1717 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
1718 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
1719 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
0316ebc4 1720
e079e414
JF
1721 if (SummerBoard_)
1722 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
1723}
e6f0817b 1724
e079e414
JF
1725MSInitialize {
1726 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
e6f0817b 1727
e079e414
JF
1728 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
1729 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
e6f0817b 1730
502d350e 1731 Manager_ = [[NSFileManager defaultManager] retain];
e079e414 1732 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
502d350e 1733
e079e414 1734 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
26c43b47 1735
e079e414 1736 // Load Settings.plist {{{
265e19b2
JF
1737 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
1738 if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
1739 SummerBoard_ = [value boolValue];
1740 if (NSNumber *value = [settings objectForKey:@"Debug"])
1741 Debug_ = [value boolValue];
62b2dbad 1742
265e19b2 1743 NSArray *themes([settings objectForKey:@"Themes"]);
d5fb6e01
JF
1744 if (themes == nil)
1745 if (NSString *theme = [settings objectForKey:@"Theme"])
1746 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
1747 theme, @"Name",
95a5777b 1748 [NSNumber numberWithBool:true], @"Active",
d5fb6e01 1749 nil]];
265e19b2 1750
d5fb6e01
JF
1751 if (themes != nil)
1752 for (NSDictionary *theme in themes) {
265e19b2 1753 NSNumber *active([theme objectForKey:@"Active"]);
d5fb6e01
JF
1754 if (![active boolValue])
1755 continue;
26c43b47 1756
265e19b2 1757 NSString *name([theme objectForKey:@"Name"]);
d5fb6e01
JF
1758 if (name == nil)
1759 continue;
1760
265e19b2 1761 NSString *theme(nil);
d5fb6e01 1762
95a5777b
JF
1763 #define testForTheme(format...) \
1764 if (theme == nil) { \
1765 NSString *path = [NSString stringWithFormat:format]; \
1766 if ([Manager_ fileExistsAtPath:path]) { \
e079e414 1767 [Themes_ addObject:path]; \
95a5777b
JF
1768 continue; \
1769 } \
d5fb6e01 1770 }
d5fb6e01 1771
95a5777b
JF
1772 testForTheme(@"/Library/Themes/%@.theme", name)
1773 testForTheme(@"/Library/Themes/%@", name)
1774 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
265e19b2 1775
d5fb6e01 1776 }
26c43b47 1777 }
e079e414
JF
1778 // }}}
1779 // Merge Info.plist {{{
d5fb6e01
JF
1780 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1781
e079e414 1782 for (NSString *theme in Themes_)
265e19b2 1783 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
d5fb6e01
JF
1784 for (NSString *key in [info allKeys])
1785 if ([Info_ objectForKey:key] == nil)
1786 [Info_ setObject:[info objectForKey:key] forKey:key];
e079e414 1787 // }}}
95a5777b 1788
e079e414
JF
1789 // AudioToolbox {{{
1790 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
1791 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
1792 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
1793 }
1794 // }}}
1795 // GraphicsServices {{{
1796 if (true) {
1797 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
1798 }
1799 // }}}
1800 // ImageIO {{{
1801 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO")) {
1802 void *(*CGImageReadCreateWithFile)(NSString *, int);
1803 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
1804 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
1805 }
1806 // }}}
1807 // SpringBoard {{{
1808 if (SpringBoard_) {
39271ad2 1809 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
e079e414 1810 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]);
8b94f6b0 1811
95a5777b
JF
1812 CFNotificationCenterAddObserver(
1813 CFNotificationCenterGetDarwinNotifyCenter(),
1814 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
1815 );
62b2dbad 1816
cc46954c 1817 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
265e19b2
JF
1818 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
1819 if (MediaPlayer != nil)
1820 [MediaPlayer load];
1821
1822 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
1823 $MPVideoView = objc_getClass("MPVideoView");
cc46954c 1824 }
2acbe5b8 1825
e079e414 1826 SBInitialize();
2acbe5b8 1827 }
e079e414
JF
1828 // }}}
1829 // UIKit {{{
1830 if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) {
1831 struct nlist nl[6];
1832 memset(nl, 0, sizeof(nl));
1833 nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName";
1834 nl[1].n_un.n_name = (char *) "__UIImageWithNameInDomain";
1835 nl[2].n_un.n_name = (char *) "__UIKitBundle";
1836 nl[3].n_un.n_name = (char *) "__UIPackedImageTableGetIdentifierForName";
1837 nl[4].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
1838 nlist(UIKit, nl);
2acbe5b8 1839
e079e414
JF
1840 nlset(_UIApplicationImageWithName, nl, 0);
1841 nlset(_UIImageWithNameInDomain, nl, 1);
1842 nlset(_UIKitBundle, nl, 2);
1843 nlset(_UIPackedImageTableGetIdentifierForName, nl, 3);
1844 nlset(_UISharedImageNameGetIdentifier, nl, 4);
1d3b613f 1845
e079e414
JF
1846 MSHookFunction(_UIApplicationImageWithName, &$_UIApplicationImageWithName, &__UIApplicationImageWithName);
1847 MSHookFunction(_UIImageWithName, &$_UIImageWithName, &__UIImageWithName);
1848 MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &__UIImageWithNameInDomain);
1849 }
1850 // }}}
77d89d52 1851
d5168fd6
JF
1852 [pool release];
1853}