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