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