]> git.saurik.com Git - winterboard.git/blame - Library.mm
Use consistent argument order for WBCacheImage().
[winterboard.git] / Library.mm
CommitLineData
d5168fd6 1/* WinterBoard - Theme Manager for the iPhone
900dc9a5 2 * Copyright (C) 2008-2014 Jay Freeman (saurik)
d5168fd6
JF
3*/
4
900dc9a5 5/* GNU Lesser General Public License, Version 3 {{{ */
d5168fd6 6/*
900dc9a5
JF
7 * WinterBoard is free software: you can redistribute it and/or modify it under
8 * the terms of the GNU Lesser General Public License as published by the
9 * Free Software Foundation, either version 3 of the License, or (at your
10 * option) any later version.
d5168fd6 11 *
900dc9a5
JF
12 * WinterBoard is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 * License for more details.
d5168fd6 16 *
900dc9a5
JF
17 * You should have received a copy of the GNU Lesser General Public License
18 * along with WinterBoard. If not, see <http://www.gnu.org/licenses/>.
19**/
20/* }}} */
d5168fd6 21
69550bfb
JF
22#include <sys/time.h>
23
24struct timeval _ltv;
25bool _itv;
26
27#define _trace() do { \
28 struct timeval _ctv; \
29 gettimeofday(&_ctv, NULL); \
30 if (!_itv) { \
31 _itv = true; \
32 _ltv = _ctv; \
33 } \
5f80b386 34 NSLog(@"%lu.%.6u[%f]:WB:_trace()@%s:%u[%s]\n", \
69550bfb
JF
35 _ctv.tv_sec, _ctv.tv_usec, \
36 (_ctv.tv_sec - _ltv.tv_sec) + (_ctv.tv_usec - _ltv.tv_usec) / 1000000.0, \
37 __FILE__, __LINE__, __FUNCTION__\
38 ); \
39 _ltv = _ctv; \
40} while (false)
41
ca13798d 42#define _transient
62b2dbad 43
e6f0817b 44#import <CoreFoundation/CoreFoundation.h>
d5168fd6 45#import <Foundation/Foundation.h>
2435118f 46#import <CoreGraphics/CoreGraphics.h>
f64efe8d 47#import <ImageIO/CGImageSource.h>
d5168fd6 48
d806256e
JF
49#import <Celestial/AVController.h>
50#import <Celestial/AVItem.h>
51#import <Celestial/AVQueue.h>
52
2acbe5b8
JF
53#include <substrate.h>
54
4668cd8e 55#import <UIKit/UIKit.h>
d5168fd6
JF
56
57#import <SpringBoard/SBApplication.h>
394d1eb5 58#import <SpringBoard/SBApplicationIcon.h>
d5168fd6 59#import <SpringBoard/SBAppWindow.h>
9cfe3924 60#import <SpringBoard/SBAwayView.h>
502d350e 61#import <SpringBoard/SBBookmarkIcon.h>
62b2dbad 62#import <SpringBoard/SBButtonBar.h>
e6f0817b 63#import <SpringBoard/SBCalendarIconContentsView.h>
95a5777b 64#import <SpringBoard/SBIconController.h>
889cb4f2 65#import <SpringBoard/SBIconLabel.h>
a8d008e4 66#import <SpringBoard/SBIconList.h>
98fe8d52 67#import <SpringBoard/SBIconModel.h>
82b4a0bd 68#import <SpringBoard/SBImageCache.h>
1a4ffdf8 69// XXX: #import <SpringBoard/SBSearchView.h>
9c64bab2 70#import <SpringBoard/SBSearchTableViewCell.h>
08454e3a 71#import <SpringBoard/SBStatusBarContentsView.h>
d5fb6e01 72#import <SpringBoard/SBStatusBarController.h>
4668cd8e 73#import <SpringBoard/SBStatusBarOperatorNameView.h>
08454e3a 74#import <SpringBoard/SBStatusBarTimeView.h>
d5168fd6 75#import <SpringBoard/SBUIController.h>
4f1b7acd 76#import <SpringBoard/SBWidgetApplicationIcon.h>
d5168fd6 77
4668cd8e
JF
78#import <MobileSMS/mSMSMessageTranscriptController.h>
79
d806256e 80#import <MediaPlayer/MPMoviePlayerController.h>
d5fb6e01
JF
81#import <MediaPlayer/MPVideoView.h>
82#import <MediaPlayer/MPVideoView-PlaybackControl.h>
83
d5168fd6
JF
84#import <CoreGraphics/CGGeometry.h>
85
198eb03b
JF
86#import <ChatKit/CKMessageCell.h>
87
609e1cd8
JF
88#include <sys/sysctl.h>
89
2de63e63
JF
90#include "WBMarkup.h"
91
ff395230
JF
92static void (*$objc_setAssociatedObject)(id object, void *key, id value, objc_AssociationPolicy policy);
93static id (*$objc_getAssociatedObject)(id object, void *key);
94static void (*$objc_removeAssociatedObjects)(id object);
95
0316ebc4
JF
96@protocol WinterBoard
97- (void *) _node;
98@end
99
d806256e 100Class $MPMoviePlayerController;
95a5777b 101Class $MPVideoView;
e079e414
JF
102
103MSClassHook(NSBundle)
32677d9d 104MSClassHook(NSString)
e079e414 105
d6f0973b 106MSClassHook(_UIAssetManager)
e079e414 107MSClassHook(UIImage)
eae989a3 108MSMetaClassHook(UIImage)
e079e414 109MSClassHook(UINavigationBar)
0f6dbbda 110MSClassHook(UISharedArtwork)
e079e414 111MSClassHook(UIToolbar)
8f0ba4d8 112MSClassHook(UIStatusBarTimeItemView)
797e4164 113MSClassHook(UIWebDocumentView)
e079e414 114
6de35b7f 115MSClassHook(CKBalloonView)
e079e414
JF
116MSClassHook(CKMessageCell)
117MSClassHook(CKTimestampView)
a06fac53 118MSClassHook(CKTranscriptCell)
e079e414 119MSClassHook(CKTranscriptController)
116c5704 120MSClassHook(CKTranscriptHeaderView)
e079e414
JF
121MSClassHook(CKTranscriptTableView)
122
123MSClassHook(SBApplication)
124MSClassHook(SBApplicationIcon)
125MSClassHook(SBAwayView)
126MSClassHook(SBBookmarkIcon)
127MSClassHook(SBButtonBar)
19fe3063 128MSClassHook(SBCalendarApplicationIcon)
e079e414
JF
129MSClassHook(SBCalendarIconContentsView)
130MSClassHook(SBDockIconListView)
131MSClassHook(SBIcon)
c40f4c11
JF
132MSClassHook(SBIconAccessoryImage)
133MSMetaClassHook(SBIconAccessoryImage)
e079e414 134MSClassHook(SBIconBadge)
19fe3063 135MSClassHook(SBIconBadgeFactory)
c40f4c11 136MSClassHook(SBIconBadgeImage)
d1779636
JF
137MSClassHook(SBIconBadgeView)
138MSMetaClassHook(SBIconBadgeView)
fce9dc59 139MSClassHook(SBIconContentView)
e079e414
JF
140MSClassHook(SBIconController)
141MSClassHook(SBIconLabel)
ff395230
JF
142MSClassHook(SBIconLabelImage)
143MSMetaClassHook(SBIconLabelImage)
144MSClassHook(SBIconLabelImageParameters)
e079e414
JF
145MSClassHook(SBIconList)
146MSClassHook(SBIconModel)
ff395230
JF
147MSClassHook(SBIconView)
148MSMetaClassHook(SBIconView)
e079e414
JF
149//MSClassHook(SBImageCache)
150MSClassHook(SBSearchView)
151MSClassHook(SBSearchTableViewCell)
eae989a3 152MSClassHook(SBSlidingAlertDisplay)
e079e414
JF
153MSClassHook(SBStatusBarContentsView)
154MSClassHook(SBStatusBarController)
155MSClassHook(SBStatusBarOperatorNameView)
156MSClassHook(SBStatusBarTimeView)
157MSClassHook(SBUIController)
eae989a3 158MSClassHook(SBWallpaperView)
e079e414
JF
159MSClassHook(SBWidgetApplicationIcon)
160
19fe3063
JF
161extern "C" void WKSetCurrentGraphicsContext(CGContextRef);
162
2a606c6c 163static struct MSFixClass { MSFixClass() {
797e4164 164 $UIWebDocumentView = objc_getClass("UIWebBrowserView") ?: $UIWebDocumentView;
2a606c6c
JF
165 $SBIcon = objc_getClass("SBIconView") ?: $SBIcon;
166
fce9dc59
JF
167 if ($SBIconList == nil)
168 $SBIconList = objc_getClass("SBIconListView");
e079e414
JF
169 if ($CKTranscriptController == nil)
170 $CKTranscriptController = objc_getClass("mSMSMessageTranscriptController");
2a606c6c 171} } MSFixClass;
8e4d2f42 172
1d3b613f 173static bool IsWild_;
e079e414 174static bool Four_($SBDockIconListView != nil);
1d3b613f 175
c40f4c11
JF
176@interface NSObject (wb$SBIconAccessoryImage)
177+ (Class) _imageClassForIcon:(SBIcon *)icon location:(int)location;
178@end
179
26c43b47 180@interface NSDictionary (WinterBoard)
37351a17
JF
181- (UIColor *) wb$colorForKey:(NSString *)key;
182- (BOOL) wb$boolForKey:(NSString *)key;
26c43b47
JF
183@end
184
185@implementation NSDictionary (WinterBoard)
186
37351a17 187- (UIColor *) wb$colorForKey:(NSString *)key {
26c43b47
JF
188 NSString *value = [self objectForKey:key];
189 if (value == nil)
190 return nil;
191 /* XXX: incorrect */
192 return nil;
193}
194
37351a17 195- (BOOL) wb$boolForKey:(NSString *)key {
889cb4f2
JF
196 if (NSString *value = [self objectForKey:key])
197 return [value boolValue];
95a5777b 198 return false;
889cb4f2
JF
199}
200
26c43b47
JF
201@end
202
d6f0973b
JF
203@interface _UIAssetManager : NSObject
204- (NSBundle *) bundle;
205- (NSString *) carFileName;
206@end
207
81decb42
JF
208static BOOL (*_GSFontGetUseLegacyFontMetrics)();
209#define $GSFontGetUseLegacyFontMetrics() \
210 (_GSFontGetUseLegacyFontMetrics == NULL ? YES : _GSFontGetUseLegacyFontMetrics())
211
bae02419 212static bool Debug_ = false;
603984d9 213static bool UIDebug_ = false;
bae02419 214static bool Engineer_ = false;
d236b808 215static bool SummerBoard_ = false;
bae02419 216static bool SpringBoard_;
889cb4f2 217
4df9352e 218static UIImage *(*_UIApplicationImageWithName)(NSString *name);
4df9352e
JF
219static UIImage *(*_UIImageWithNameInDomain)(NSString *name, NSString *domain);
220static NSBundle *(*_UIKitBundle)();
4df9352e 221
0db8a084 222static NSMutableDictionary *Images_ = [[NSMutableDictionary alloc] initWithCapacity:64];
e079e414
JF
223static NSMutableDictionary *Cache_ = [[NSMutableDictionary alloc] initWithCapacity:64];
224static NSMutableDictionary *Strings_ = [[NSMutableDictionary alloc] initWithCapacity:0];
225static NSMutableDictionary *Bundles_ = [[NSMutableDictionary alloc] initWithCapacity:2];
2435118f 226
502d350e 227static NSFileManager *Manager_;
e079e414
JF
228static NSMutableArray *Themes_;
229
502d350e
JF
230static NSDictionary *English_;
231static NSMutableDictionary *Info_;
d5168fd6 232
d6f0973b
JF
233// @interface WBBundle {{{
234@interface WBBundle : NSBundle {
235 NSString *identifier_;
236}
237
238+ (WBBundle *) bundleWithIdentifier:(NSString *)identifier;
239
240@end
241
242@implementation WBBundle
243
244- (void) dealloc {
245 [identifier_ release];
246 return [super dealloc];
247}
248
249+ (WBBundle *) bundleWithIdentifier:(NSString *)identifier {
250 return [[[self alloc] initWithIdentifier:identifier] autorelease];
251}
252
253- (id) initWithIdentifier:(NSString *)identifier {
254 if ((self = [super init]) != nil) {
255 identifier_ = [identifier retain];
256 } return self;
257}
258
259- (NSString *) bundleIdentifier {
260 return identifier_;
261}
262
263@end
264// }}}
265
e079e414
JF
266// $getTheme$() {{{
267static NSMutableDictionary *Themed_ = [[NSMutableDictionary alloc] initWithCapacity:128];
268
269static unsigned Scale_ = 0;
270
5b21732c
JF
271static unsigned $getScale$(NSString *path) {
272 NSString *name(path);
273
274 #define StripName(strip) \
275 if ([name hasSuffix:@ strip]) \
276 name = [name substringWithRange:NSMakeRange(0, [name length] - sizeof(strip) - 1)];
277
278 StripName(".png");
279 StripName(".jpg");
280 StripName("~iphone");
281 StripName("~ipad");
282
240a7a4e
JF
283 if ([name hasSuffix:@"@3x"])
284 return 3;
285 if ([name hasSuffix:@"@2x"])
286 return 2;
287 return 1;
5b21732c
JF
288}
289
39271ad2 290static NSArray *$useScale$(NSArray *files, bool use = true) {
e05a7e78 291 if (use && Scale_ == 0) {
e079e414
JF
292 UIScreen *screen([UIScreen mainScreen]);
293 if ([screen respondsToSelector:@selector(scale)])
294 Scale_ = [screen scale];
295 else
296 Scale_ = 1;
297 }
e839c3fe 298
f6bf440f
JF
299 NSString *idiom(IsWild_ ? @"ipad" : @"iphone");
300
301 NSMutableArray *scaled([NSMutableArray arrayWithCapacity:([files count] * 4)]);
39271ad2
JF
302
303 for (NSString *file in files) {
f6bf440f
JF
304 NSString *base([file stringByDeletingPathExtension]);
305 NSString *extension([file pathExtension]);
306
307 if (use) {
240a7a4e
JF
308 for (unsigned scale(2); scale <= Scale_; ++scale) {
309 [scaled addObject:[NSString stringWithFormat:@"%@@%ux~%@.%@", base, scale, idiom, extension]];
310 [scaled addObject:[NSString stringWithFormat:@"%@@%ux.%@", base, scale, extension]];
f6bf440f
JF
311 }
312
313 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
314
315 // if (!IsWild_) <- support old themes
316 [scaled addObject:file];
240a7a4e 317 } else if ([base hasSuffix: @"@2x"] || [base hasSuffix:@"@3x"]) {
843a7f3c 318 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]];
f6bf440f
JF
319 [scaled addObject:file];
320
07591533
JF
321 // XXX: this actually can't be used, as the person loading the file doesn't realize that the @2x changed
322 /*NSString *rest([base substringWithRange:NSMakeRange(0, [base length] - 3)]);
843a7f3c 323 [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", rest, idiom, extension]];
07591533 324 [scaled addObject:[rest stringByAppendingPathExtension:extension]];*/
f6bf440f
JF
325 } else {
326 // XXX: this code isn't really complete
327
328 [scaled addObject:file];
329
843a7f3c
JF
330 if ([base hasSuffix:[NSString stringWithFormat:@"~%@", idiom]])
331 [scaled addObject:[[base substringWithRange:NSMakeRange(0, [base length] - 1 - [idiom length])] stringByAppendingPathExtension:extension]];
f6bf440f 332 }
39271ad2
JF
333 }
334
335 return scaled;
336}
337
ecf154db 338static NSString *$getTheme$(NSArray *files, NSArray *themes = Themes_) {
7c0f4e8c
JF
339 // XXX: this is not reasonable; OMG
340 id key(files);
341
342 @synchronized (Themed_) {
343 if (NSString *path = [Themed_ objectForKey:key])
344 return reinterpret_cast<id>(path) == [NSNull null] ? nil : path;
345 }
39271ad2 346
2acbe5b8
JF
347 if (Debug_)
348 NSLog(@"WB:Debug: %@", [files description]);
349
e839c3fe
JF
350 NSString *path;
351
e079e414 352 for (NSString *theme in Themes_)
502d350e 353 for (NSString *file in files) {
e839c3fe 354 path = [NSString stringWithFormat:@"%@/%@", theme, file];
9e0a075f 355 if ([Manager_ fileExistsAtPath:path]) {
fdac1738 356 if ([[Manager_ destinationOfSymbolicLinkAtPath:path error:NULL] isEqualToString:@"/"])
9e0a075f 357 path = nil;
e839c3fe 358 goto set;
9e0a075f 359 }
502d350e
JF
360 }
361
e839c3fe
JF
362 path = nil;
363 set:
e079e414 364
7c0f4e8c
JF
365 @synchronized (Themed_) {
366 [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:key];
367 }
368
e839c3fe 369 return path;
502d350e 370}
e079e414
JF
371// }}}
372// $pathForFile$inBundle$() {{{
00c922e0 373static void $pathForFile$inBundle$(NSMutableArray *names, NSString *file, NSString *identifier, NSString *folder) {
4df9352e
JF
374 if (identifier != nil)
375 [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]];
00c922e0 376 if (folder != nil) {
4df9352e 377 [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]];
fa2bffc4
JF
378 NSString *base([folder stringByDeletingPathExtension]);
379 if ([base hasSuffix:@"~iphone"])
380 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 7)], [folder pathExtension], file]];
843a7f3c
JF
381 if ([base hasSuffix:@"~ipad"])
382 [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 5)], [folder pathExtension], file]];
fa2bffc4 383 }
4df9352e
JF
384
385 #define remapResourceName(oldname, newname) \
77d89d52 386 else if ([file isEqualToString:(oldname)]) \
1d3537b4 387 [names addObject:oldname ".png"];
4df9352e 388
bae02419
JF
389 bool summer(SpringBoard_ && SummerBoard_);
390
4df9352e 391 if (identifier == nil);
d6f0973b 392 else if ([identifier isEqualToString:@"com.apple.uikit.Artwork"])
e9c2cd65 393 $pathForFile$inBundle$(names, file, @"com.apple.UIKit", @"UIKit.framework");
d6f0973b 394 else if ([identifier isEqualToString:@"com.apple.uikit.LegacyArtwork"])
e9c2cd65 395 $pathForFile$inBundle$(names, file, @"com.apple.UIKit", @"UIKit.framework");
d9ea6cd5
JF
396 else if ([identifier isEqualToString:@"com.apple.UIKit"])
397 [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
198eb03b 398 else if ([identifier isEqualToString:@"com.apple.chatkit"])
e9c2cd65 399 $pathForFile$inBundle$(names, file, @"com.apple.MobileSMS", @"MobileSMS.app");
4df9352e
JF
400 else if ([identifier isEqualToString:@"com.apple.calculator"])
401 [names addObject:[NSString stringWithFormat:@"Files/Applications/Calculator.app/%@", file]];
7cee32a1 402 else if ([identifier isEqualToString:@"com.apple.Maps"] && [file isEqualToString:@"Icon-57@2x.png"])
b704c082 403 $pathForFile$inBundle$(names, @"icon.png", identifier, folder);
bae02419 404 else if (!summer);
4df9352e 405 remapResourceName(@"FSO_BG.png", @"StatusBar")
77d89d52 406 remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock")
4df9352e 407 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
d6f0973b 408}
4df9352e 409
fabdff02 410static NSString *$pathForFile$inBundle$(NSString *file, NSString *identifier, NSURL *url, bool use) {
d6f0973b 411 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
00c922e0 412 $pathForFile$inBundle$(names, file, identifier, [url lastPathComponent]);
705e6795 413 [names addObject:[NSString stringWithFormat:@"Fallback/%@", file]];
01679825 414 if (NSString *path = $getTheme$($useScale$(names, use)))
4df9352e
JF
415 return path;
416 return nil;
417}
fabdff02
JF
418
419// XXX: this cannot be merged due to WBBundle
420static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool use) {
421 return $pathForFile$inBundle$(file, [bundle bundleIdentifier], [bundle bundleURL], use);
422}
423
424static NSString *$pathForFile$inBundle$(NSString *file, CFBundleRef bundle, bool use) {
425 NSString *identifier((NSString *) CFBundleGetIdentifier(bundle));
426 NSURL *url([(NSURL *) CFBundleCopyBundleURL(bundle) autorelease]);
427 return $pathForFile$inBundle$(file, identifier, url, use);
428}
e079e414 429// }}}
4df9352e 430
ab3ce88d 431static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") {
2acbe5b8
JF
432 NSString *identifier = [self bundleIdentifier];
433 NSString *path = [self path];
434 NSString *folder = [path lastPathComponent];
435 NSString *dname = [self displayName];
2940a99f
JF
436
437 NSString *didentifier;
438 if ([self respondsToSelector:@selector(displayIdentifier)])
439 didentifier = [self displayIdentifier];
440 else
441 didentifier = nil;
d5fb6e01 442
2acbe5b8
JF
443 if (Debug_)
444 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
62b2dbad 445
2acbe5b8 446 NSMutableArray *names = [NSMutableArray arrayWithCapacity:8];
d5fb6e01 447
265e19b2 448 /* XXX: I might need to keep this for backwards compatibility
2acbe5b8
JF
449 if (identifier != nil)
450 [names addObject:[NSString stringWithFormat:@"Bundles/%@/icon.png", identifier]];
451 if (folder != nil)
265e19b2 452 [names addObject:[NSString stringWithFormat:@"Folders/%@/icon.png", folder]]; */
889cb4f2 453
2acbe5b8
JF
454 #define testForIcon(Name) \
455 if (NSString *name = Name) \
ab3ce88d 456 [names addObject:[NSString stringWithFormat:@"Icons%@/%@.png", suffix, name]];
ca13798d 457
2940a99f 458 if (didentifier != nil && ![didentifier isEqualToString:identifier])
9e42420f 459 testForIcon(didentifier);
24ba43ee 460
2acbe5b8
JF
461 testForIcon(identifier);
462 testForIcon(dname);
889cb4f2 463
24ba43ee
JF
464 if ([identifier isEqualToString:@"com.apple.MobileSMS"])
465 testForIcon(@"SMS");
466
2acbe5b8
JF
467 if (didentifier != nil) {
468 testForIcon([English_ objectForKey:didentifier]);
889cb4f2 469
2acbe5b8
JF
470 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
471 if ([parts count] != 1)
472 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[path stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
473 testForIcon([english objectForKey:[parts lastObject]]);
d5fb6e01 474 }
889cb4f2 475
2acbe5b8
JF
476 if (NSString *path = $getTheme$(names))
477 return path;
24ba43ee 478
394d1eb5
JF
479 return nil;
480}
481
e079e414 482// -[NSBundle wb$bundleWithFile] {{{
4df9352e
JF
483@interface NSBundle (WinterBoard)
484+ (NSBundle *) wb$bundleWithFile:(NSString *)path;
485@end
486
487@implementation NSBundle (WinterBoard)
488
489+ (NSBundle *) wb$bundleWithFile:(NSString *)path {
490 path = [path stringByDeletingLastPathComponent];
491 if (path == nil || [path length] == 0 || [path isEqualToString:@"/"])
492 return nil;
493
95b8e886
JF
494 NSBundle *bundle;
495 @synchronized (Bundles_) {
496 bundle = [Bundles_ objectForKey:path];
497 }
498
4df9352e
JF
499 if (reinterpret_cast<id>(bundle) == [NSNull null])
500 return nil;
501 else if (bundle == nil) {
0316ebc4
JF
502 if ([Manager_ fileExistsAtPath:[path stringByAppendingPathComponent:@"Info.plist"]])
503 bundle = [NSBundle bundleWithPath:path];
4df9352e
JF
504 if (bundle == nil)
505 bundle = [NSBundle wb$bundleWithFile:path];
506 if (Debug_)
507 NSLog(@"WB:Debug:PathBundle(%@, %@)", path, bundle);
95b8e886
JF
508
509 @synchronized (Bundles_) {
510 [Bundles_ setObject:(bundle == nil ? [NSNull null] : reinterpret_cast<id>(bundle)) forKey:path];
511 }
4df9352e
JF
512 }
513
514 return bundle;
515}
516
517@end
e079e414
JF
518// }}}
519// -[NSString wb$themedPath] {{{
4df9352e
JF
520@interface NSString (WinterBoard)
521- (NSString *) wb$themedPath;
522@end
523
524@implementation NSString (WinterBoard)
525
526- (NSString *) wb$themedPath {
5b9ea3d9
JF
527 if ([self hasPrefix:@"/Library/Themes/"])
528 return self;
529
4df9352e
JF
530 if (Debug_)
531 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
532
533 if (NSBundle *bundle = [NSBundle wb$bundleWithFile:self]) {
534 NSString *file([self stringByResolvingSymlinksInPath]);
535 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
536 if ([file hasPrefix:prefix]) {
537 NSUInteger length([prefix length]);
538 if (length != [file length])
d9ea6cd5 539 if (NSString *path = $pathForFile$inBundle$([file substringFromIndex:(length + 1)], bundle, false))
4df9352e
JF
540 return path;
541 }
542 }
543
544 return self;
545}
546
547@end
e079e414 548// }}}
4df9352e 549
9c64bab2
JF
550void WBLogRect(const char *tag, struct CGRect rect) {
551 NSLog(@"%s:{%f,%f+%f,%f}", tag, rect.origin.x, rect.origin.y, rect.size.width, rect.size.height);
552}
553
554void WBLogHierarchy(UIView *view, unsigned index = 0, unsigned indent = 0) {
555 CGRect frame([view frame]);
198eb03b 556 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
557 index = 0;
558 for (UIView *child in [view subviews])
9c64bab2 559 WBLogHierarchy(child, index++, indent + 1);
1a4ffdf8
JF
560}
561
82b4a0bd
JF
562UIImage *$cacheForImage$(UIImage *image) {
563 CGColorSpaceRef space(CGColorSpaceCreateDeviceRGB());
564 CGRect rect = {CGPointMake(1, 1), [image size]};
565 CGSize size = {rect.size.width + 2, rect.size.height + 2};
2acbe5b8 566
82b4a0bd
JF
567 CGContextRef context(CGBitmapContextCreate(NULL, size.width, size.height, 8, 4 * size.width, space, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst));
568 CGColorSpaceRelease(space);
2acbe5b8 569
82b4a0bd
JF
570 CGContextDrawImage(context, rect, [image CGImage]);
571 CGImageRef ref(CGBitmapContextCreateImage(context));
572 CGContextRelease(context);
2acbe5b8 573
82b4a0bd
JF
574 UIImage *cache([UIImage imageWithCGImage:ref]);
575 CGImageRelease(ref);
2acbe5b8 576
82b4a0bd
JF
577 return cache;
578}
579
580/*MSHook(id, SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$, SBImageCache *self, SEL sel, NSString *name, unsigned width, unsigned height, unsigned capacity) {
581 //if ([name isEqualToString:@"icons"]) return nil;
582 return _SBImageCache$initWithName$forImageWidth$imageHeight$initialCapacity$(self, sel, name, width, height, capacity);
583}*/
584
585MSHook(void, SBIconModel$cacheImageForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
586 NSString *key([icon displayIdentifier]);
2acbe5b8 587
82b4a0bd
JF
588 if (UIImage *image = [icon icon]) {
589 CGSize size = [image size];
b0d0c73f 590 if (size.width != 59 || size.height != 60) {
82b4a0bd
JF
591 UIImage *cache($cacheForImage$(image));
592 [Cache_ setObject:cache forKey:key];
593 return;
594 }
2acbe5b8 595 }
82b4a0bd
JF
596
597 _SBIconModel$cacheImageForIcon$(self, sel, icon);
4e0efa01
JF
598}
599
1a4ffdf8
JF
600MSHook(void, SBIconModel$cacheImagesForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
601 /* XXX: do I /really/ have to do this? figure out how to cache the small icon! */
602 _SBIconModel$cacheImagesForIcon$(self, sel, icon);
603
604 NSString *key([icon displayIdentifier]);
605
606 if (UIImage *image = [icon icon]) {
607 CGSize size = [image size];
608 if (size.width != 59 || size.height != 60) {
609 UIImage *cache($cacheForImage$(image));
610 [Cache_ setObject:cache forKey:key];
611 return;
612 }
613 }
614}
615
0316ebc4 616MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$, SBIconModel *self, SEL sel, SBIcon *icon) {
4e0efa01
JF
617 NSString *key([icon displayIdentifier]);
618 if (UIImage *image = [Cache_ objectForKey:key])
619 return image;
620 else
0316ebc4 621 return _SBIconModel$getCachedImagedForIcon$(self, sel, icon);
4e0efa01
JF
622}
623
1a4ffdf8
JF
624MSHook(UIImage *, SBIconModel$getCachedImagedForIcon$smallIcon$, SBIconModel *self, SEL sel, SBIcon *icon, BOOL small) {
625 if (small)
626 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
627 NSString *key([icon displayIdentifier]);
628 if (UIImage *image = [Cache_ objectForKey:key])
629 return image;
630 else
631 return _SBIconModel$getCachedImagedForIcon$smallIcon$(self, sel, icon, small);
632}
633
634MSHook(id, SBSearchView$initWithFrame$, id /* XXX: SBSearchView */ self, SEL sel, struct CGRect frame) {
635 if ((self = _SBSearchView$initWithFrame$(self, sel, frame)) != nil) {
636 [self setBackgroundColor:[UIColor clearColor]];
637 for (UIView *child in [self subviews])
638 [child setBackgroundColor:[UIColor clearColor]];
639 } return self;
640}
641
9c64bab2
JF
642MSHook(id, SBSearchTableViewCell$initWithStyle$reuseIdentifier$, SBSearchTableViewCell *self, SEL sel, int style, NSString *reuse) {
643 if ((self = _SBSearchTableViewCell$initWithStyle$reuseIdentifier$(self, sel, style, reuse)) != nil) {
644 [self setBackgroundColor:[UIColor clearColor]];
645 } return self;
646}
647
648MSHook(void, SBSearchTableViewCell$drawRect$, SBSearchTableViewCell *self, SEL sel, struct CGRect rect, BOOL selected) {
649 _SBSearchTableViewCell$drawRect$(self, sel, rect, selected);
650 float inset([self edgeInset]);
651 [[UIColor clearColor] set];
652 UIRectFill(CGRectMake(0, 0, inset, rect.size.height));
653 UIRectFill(CGRectMake(rect.size.width - inset, 0, inset, rect.size.height));
654}
655
0316ebc4 656MSHook(UIImage *, SBApplicationIcon$icon, SBApplicationIcon *self, SEL sel) {
37351a17 657 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"])
56539693 658 if (NSString *path = $pathForIcon$([self application]))
2acbe5b8 659 return [UIImage imageWithContentsOfFile:path];
0316ebc4 660 return _SBApplicationIcon$icon(self, sel);
394d1eb5
JF
661}
662
1d3b613f
JF
663MSHook(UIImage *, SBApplicationIcon$generateIconImage$, SBApplicationIcon *self, SEL sel, int type) {
664 if (type == 2)
ab3ce88d 665 if (![Info_ wb$boolForKey:@"ComposeStoreIcons"]) {
f53378dc 666 if (IsWild_ && false) // XXX: delete this code, it should not be supported
77d89d52
JF
667 if (NSString *path72 = $pathForIcon$([self application], @"-72"))
668 return [UIImage imageWithContentsOfFile:path72];
669 if (NSString *path = $pathForIcon$([self application]))
670 if (UIImage *image = [UIImage imageWithContentsOfFile:path]) {
0fa37711 671 CGFloat width;
77d89d52
JF
672 if ([$SBIcon respondsToSelector:@selector(defaultIconImageSize)])
673 width = [$SBIcon defaultIconImageSize].width;
674 else
675 width = 59;
676 return width == 59 ? image : [image _imageScaledToProportion:(width / 59.0) interpolationQuality:5];
677 }
ab3ce88d 678 }
1d3b613f
JF
679 return _SBApplicationIcon$generateIconImage$(self, sel, type);
680}
681
4f1b7acd 682MSHook(UIImage *, SBWidgetApplicationIcon$icon, SBWidgetApplicationIcon *self, SEL sel) {
d806256e
JF
683 if (Debug_)
684 NSLog(@"WB:Debug:Widget(%@:%@)", [self displayIdentifier], [self displayName]);
685 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
4f1b7acd 686 return [UIImage imageWithContentsOfFile:path];
d806256e 687 return _SBWidgetApplicationIcon$icon(self, sel);
4f1b7acd
JF
688}
689
0316ebc4 690MSHook(UIImage *, SBBookmarkIcon$icon, SBBookmarkIcon *self, SEL sel) {
502d350e
JF
691 if (Debug_)
692 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
693 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
2acbe5b8 694 return [UIImage imageWithContentsOfFile:path];
0316ebc4 695 return _SBBookmarkIcon$icon(self, sel);
502d350e
JF
696}
697
0316ebc4 698MSHook(NSString *, SBApplication$pathForIcon, SBApplication *self, SEL sel) {
d5fb6e01
JF
699 if (NSString *path = $pathForIcon$(self))
700 return path;
0316ebc4 701 return _SBApplication$pathForIcon(self, sel);
d5168fd6
JF
702}
703
95a5777b 704static UIImage *CachedImageAtPath(NSString *path) {
4df9352e 705 path = [path stringByResolvingSymlinksInPath];
0db8a084 706 UIImage *image = [Images_ objectForKey:path];
95a5777b
JF
707 if (image != nil)
708 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
4df9352e 709 image = [[UIImage alloc] initWithContentsOfFile:path cache:true];
95a5777b
JF
710 if (image != nil)
711 image = [image autorelease];
0db8a084 712 [Images_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
95a5777b
JF
713 return image;
714}
715
4df9352e 716MSHook(UIImage *, _UIApplicationImageWithName, NSString *name) {
d5fb6e01
JF
717 NSBundle *bundle = [NSBundle mainBundle];
718 if (Debug_)
4df9352e 719 NSLog(@"WB:Debug: _UIApplicationImageWithName(\"%@\", %@)", name, bundle);
d9ea6cd5 720 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
95a5777b 721 return CachedImageAtPath(path);
4df9352e 722 return __UIApplicationImageWithName(name);
502d350e
JF
723}
724
502d350e
JF
725#define WBDelegate(delegate) \
726 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
727 if (Engineer_) \
728 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
729 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
730 return sig; \
731 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
732 return nil; \
733 } \
734\
735 - (void) forwardInvocation:(NSInvocation*)inv { \
736 SEL sel = [inv selector]; \
737 if ([delegate respondsToSelector:sel]) \
738 [inv invokeWithTarget:delegate]; \
739 else \
740 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
741 }
742
fabdff02
JF
743// %hook CFBundleCopyResourceURL {{{
744MSHook(CFURLRef, CFBundleCopyResourceURL, CFBundleRef bundle, CFStringRef resourceName, CFStringRef resourceType, CFStringRef subDirName) {
745 NSString *file((NSString *) resourceName);
746 if (resourceType != NULL)
747 file = [NSString stringWithFormat:@"%@.%@", file, resourceType];
748 if (subDirName != NULL)
749 file = [NSString stringWithFormat:@"%@/%@", subDirName, resourceType];
750
889cb4f2 751 if (Debug_)
fabdff02
JF
752 NSLog(@"WB:Debug: CFBundleCopyResourceURL(<%@>, \"%@\", \"%@\", \"%@\")", CFBundleGetIdentifier(bundle), resourceName, resourceType, subDirName);
753 if (NSString *path = $pathForFile$inBundle$(file, bundle, false))
754 return (CFURLRef) [[NSURL alloc] initFileURLWithPath:path];
755 return _CFBundleCopyResourceURL(bundle, resourceName, resourceType, subDirName);
26c43b47 756}
e079e414 757// }}}
26c43b47 758
cdd7eee4
JF
759static void $drawLabel$(NSString *label, CGRect rect, NSString *style, NSString *custom) {
760 bool ellipsis(false);
0fa37711 761 CGFloat max = rect.size.width - 11, width;
cdd7eee4
JF
762 width:
763 width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width;
764
765 if (width > max) {
766 size_t length([label length]);
0fa37711 767 CGFloat spacing((width - max) / (length - 1));
cdd7eee4
JF
768
769 if (spacing > 1.25) {
770 ellipsis = true;
771 label = [label substringToIndex:(length - 1)];
772 goto width;
773 }
774
775 style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
776 }
777
778 if (ellipsis)
779 label = [label stringByAppendingString:@"..."];
780
781 if (custom != nil)
782 style = [style stringByAppendingString:custom];
783
784 CGSize size = [label sizeWithStyle:style forWidth:rect.size.width];
c570f7cb 785 [label drawAtPoint:CGPointMake((rect.size.width - size.width) / 2 + rect.origin.x, rect.origin.y) withStyle:style];
cdd7eee4
JF
786}
787
19fe3063
JF
788static struct WBStringDrawingState {
789 WBStringDrawingState *next_;
cc5f5e5d 790 unsigned count_;
1ed87fae
JF
791 NSString *base_;
792 NSString *info_;
19fe3063
JF
793} *stringDrawingState_;
794
367bcc25
JF
795extern "C" CGColorSpaceRef CGContextGetFillColorSpace(CGContextRef);
796extern "C" void CGContextGetFillColor(CGContextRef, CGFloat[]);
797
d1779636 798static NSString *WBColorMarkup(size_t number, const CGFloat *components) {
367bcc25
JF
799 CGFloat r, g, b, a;
800
801 switch (number) {
802 case 1:
803 r = components[0];
804 g = components[0];
805 b = components[0];
806 a = components[1];
807 break;
808
809 case 3:
810 r = components[0];
811 g = components[1];
812 b = components[2];
813 a = components[3];
814 break;
815
816 default:
817 return @"";
818 }
819
820 return [NSString stringWithFormat:@"color: rgba(%g, %g, %g, %g)", r * 255, g * 255, b * 255, a];
821}
822
d1779636
JF
823static NSString *WBColorMarkup() {
824 CGContextRef context(UIGraphicsGetCurrentContext());
825 //NSLog(@"XXX:1:%p", context);
826 if (context == NULL)
827 return @"";
828
829 CGColorSpaceRef space(CGContextGetFillColorSpace(context));
830 //NSLog(@"XXX:2:%p", space);
831 if (space == NULL)
832 return @"";
833
834 size_t number(CGColorSpaceGetNumberOfComponents(space));
835 //NSLog(@"XXX:3:%u", number);
836 if (number == 0)
837 return @"";
838
839 CGFloat components[number + 1];
840 CGContextGetFillColor(context, components);
841 return WBColorMarkup(number, components);
842}
843
844static NSString *WBColorMarkup(UIColor *uicolor) {
845 if (uicolor == nil)
846 return @"";
847 CGColorRef cgcolor([uicolor CGColor]);
848 if (cgcolor == NULL)
849 return @"";
850
851 CGColorSpaceRef space(CGColorGetColorSpace(cgcolor));
852 //NSLog(@"XXX:2:%p", space);
853 if (space == NULL)
854 return @"";
855
856 size_t number(CGColorGetNumberOfComponents(cgcolor));
857 //NSLog(@"XXX:3:%u", number);
858 if (number == 0)
859 return @"";
860
861 const CGFloat *components(CGColorGetComponents(cgcolor));
862 return WBColorMarkup(number, components);
863}
864
e4cbfc3e
JF
865extern "C" NSString *NSStringFromCGPoint(CGPoint rect);
866
712d0089
JF
867MSInstanceMessage6(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode,letterSpacing,includeEmoji, CGPoint, point, CGFloat, width, UIFont *, font, UILineBreakMode, mode, CGFloat, spacing, BOOL, emoji) {
868 //NSLog(@"XXX: @\"%@\" %@ %g \"%@\" %u %g %u", self, NSStringFromCGPoint(point), width, font, mode, spacing, emoji);
cc11d828 869
cc5f5e5d
JF
870 WBStringDrawingState *state(stringDrawingState_);
871 if (state == NULL)
712d0089 872 return MSOldCall(point, width, font, mode, spacing, emoji);
19fe3063 873
72bd96ab 874 if (state->count_ != 0 && --state->count_ == 0)
cc5f5e5d
JF
875 stringDrawingState_ = state->next_;
876 if (state->info_ == nil)
712d0089 877 return MSOldCall(point, width, font, mode, spacing, emoji);
19fe3063 878
cc5f5e5d
JF
879 NSString *info([Info_ objectForKey:state->info_]);
880 if (info == nil)
712d0089 881 return MSOldCall(point, width, font, mode, spacing, emoji);
19fe3063 882
cc5f5e5d 883 NSString *base(state->base_ ?: @"");
09eac582 884 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
367bcc25 885 [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
19fe3063
JF
886 return CGSizeZero;
887}
888
cc11d828
JF
889extern "C" NSString *NSStringFromCGRect(CGRect rect);
890
c8fa3a18 891MSInstanceMessageHook7(CGSize, NSString, _drawInRect,withFont,lineBreakMode,alignment,lineSpacing,includeEmoji,truncationRect, CGRect, rect, UIFont *, font, UILineBreakMode, mode, UITextAlignment, alignment, float, spacing, BOOL, emoji, CGRect, truncation) {
e4cbfc3e 892 //NSLog(@"XXX: @\"%@\" %@ \"%@\" %u %u %g %u %@", self, NSStringFromCGRect(rect), font, mode, alignment, spacing, emoji, NSStringFromCGRect(truncation));
cc11d828 893
6cd8823c
JF
894 WBStringDrawingState *state(stringDrawingState_);
895 if (state == NULL)
a067a975 896 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
6cd8823c 897
72bd96ab 898 if (state->count_ != 0 && --state->count_ == 0)
6cd8823c
JF
899 stringDrawingState_ = state->next_;
900 if (state->info_ == nil)
a067a975 901 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
6cd8823c
JF
902
903 NSString *info([Info_ objectForKey:state->info_]);
904 if (info == nil)
a067a975 905 return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
6cd8823c 906
c27e08b2
JF
907 NSString *textAlign;
908 switch (alignment) {
909 default:
c8fa3a18 910 case UITextAlignmentLeft:
c27e08b2
JF
911 textAlign = @"left";
912 break;
c8fa3a18 913 case UITextAlignmentCenter:
c27e08b2
JF
914 textAlign = @"center";
915 break;
c8fa3a18 916 case UITextAlignmentRight:
c27e08b2
JF
917 textAlign = @"right";
918 break;
919 }
920
6cd8823c 921 NSString *base(state->base_ ?: @"");
c27e08b2 922 NSString *extra([NSString stringWithFormat:@"text-align: %@", textAlign]);
c570f7cb
JF
923
924 if (true)
367bcc25 925 $drawLabel$(self, rect, [NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], WBColorMarkup(), base], info);
c570f7cb 926 else
367bcc25 927 [self drawInRect:rect withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]];
c570f7cb 928
6cd8823c
JF
929 return CGSizeZero;
930}
931
d1779636 932MSInstanceMessage2(void, NSString, drawInRect,withAttributes, CGRect, rect, NSDictionary *, attributes) {
6fa3da59 933 //NSLog(@"XXX: *\"%@\" %@", self, attributes);
d1779636
JF
934
935 WBStringDrawingState *state(stringDrawingState_);
936 if (state == NULL)
937 return MSOldCall(rect, attributes);
938
939 if (state->count_ != 0 && --state->count_ == 0)
940 stringDrawingState_ = state->next_;
941 if (state->info_ == nil)
942 return MSOldCall(rect, attributes);
943
944 NSString *info([Info_ objectForKey:state->info_]);
945 if (info == nil)
946 return MSOldCall(rect, attributes);
947
948 NSString *base(state->base_ ?: @"");
949
950 UIFont *font([attributes objectForKey:@"NSFont"]);
951 UIColor *color([attributes objectForKey:@"NSColor"]);
952
953 [self drawInRect:rect withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(color), base, info]];
954}
955
956extern "C" NSString *NSStringFromCGSize(CGSize size);
957
958MSInstanceMessage4(CGRect, NSString, boundingRectWithSize,options,attributes,context, CGSize, size, NSInteger, options, NSDictionary *, attributes, id, context) {
6fa3da59 959 //NSLog(@"XXX: $\"%@\" %@ 0x%x %@ %@", self, NSStringFromCGSize(size), unsigned(options), attributes, context);
d1779636
JF
960
961 WBStringDrawingState *state(stringDrawingState_);
962 if (state == NULL)
963 return MSOldCall(size, options, attributes, context);
964
965 if (state->count_ != 0 && --state->count_ == 0)
966 stringDrawingState_ = state->next_;
967 if (state->info_ == nil)
968 return MSOldCall(size, options, attributes, context);
969
970 NSString *info([Info_ objectForKey:state->info_]);
971 if (info == nil)
972 return MSOldCall(size, options, attributes, context);
973
974 NSString *base(state->base_ ?: @"");
975
976 UIFont *font([attributes objectForKey:@"NSFont"]);
977 UIColor *color([attributes objectForKey:@"NSColor"]);
978
979 return (CGRect) {{0, 0}, [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(color), base, info] forWidth:size.width]};
980}
981
fd1c824a 982MSInstanceMessage4(CGSize, NSString, sizeWithFont,forWidth,lineBreakMode,letterSpacing, UIFont *, font, CGFloat, width, UILineBreakMode, mode, CGFloat, spacing) {
cc11d828
JF
983 //NSLog(@"XXX: #\"%@\" \"%@\" %g %u %g", self, font, width, mode, spacing);
984
cc5f5e5d
JF
985 WBStringDrawingState *state(stringDrawingState_);
986 if (state == NULL)
b3f846db 987 return MSOldCall(font, width, mode, spacing);
19fe3063 988
72bd96ab 989 if (state->count_ != 0 && --state->count_ == 0)
cc5f5e5d
JF
990 stringDrawingState_ = state->next_;
991 if (state->info_ == nil)
b3f846db 992 return MSOldCall(font, width, mode, spacing);
19fe3063 993
cc5f5e5d
JF
994 NSString *info([Info_ objectForKey:state->info_]);
995 if (info == nil)
b3f846db 996 return MSOldCall(font, width, mode, spacing);
19fe3063 997
cc5f5e5d 998 NSString *base(state->base_ ?: @"");
09eac582 999 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
367bcc25 1000 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info] forWidth:width];
19fe3063
JF
1001}
1002
fd1c824a 1003MSInstanceMessage1(CGSize, NSString, sizeWithFont, UIFont *, font) {
cc11d828
JF
1004 //NSLog(@"XXX: ?\"%@\"", self);
1005
cc5f5e5d
JF
1006 WBStringDrawingState *state(stringDrawingState_);
1007 if (state == NULL)
1008 return MSOldCall(font);
1009
72bd96ab 1010 if (state->count_ != 0 && --state->count_ == 0)
cc5f5e5d
JF
1011 stringDrawingState_ = state->next_;
1012 if (state->info_ == nil)
1013 return MSOldCall(font);
1014
1015 NSString *info([Info_ objectForKey:state->info_]);
1016 if (info == nil)
1017 return MSOldCall(font);
1018
1019 NSString *base(state->base_ ?: @"");
367bcc25 1020 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), base, info] forWidth:65535];
cc5f5e5d
JF
1021}
1022
d1779636
JF
1023MSClassMessageHook2(id, SBIconBadgeView, checkoutAccessoryImagesForIcon,location, id, icon, int, location) {
1024 WBStringDrawingState badgeState = {NULL, 0, @""
1025 , @"BadgeStyle"};
1026
1027 stringDrawingState_ = &badgeState;
1028
1029 id images(MSOldCall(icon, location));
1030
1031 stringDrawingState_ = NULL;
1032 return images;
1033}
1034
c40f4c11
JF
1035MSClassMessageHook2(UIImage *, SBIconAccessoryImage, checkoutAccessoryImageForIcon,location, id, icon, int, location) {
1036 if ([self _imageClassForIcon:icon location:location] != $SBIconBadgeImage)
1037 return MSOldCall(icon, location);
1038
72bd96ab 1039 WBStringDrawingState badgeState = {NULL, 0, @""
c40f4c11
JF
1040 , @"BadgeStyle"};
1041
1042 stringDrawingState_ = &badgeState;
1043
1044 UIImage *image(MSOldCall(icon, location));
1045
1046 stringDrawingState_ = NULL;
1047 return image;
1048}
1049
19fe3063 1050MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
72bd96ab 1051 WBStringDrawingState badgeState = {NULL, 0, @""
19fe3063
JF
1052 , @"BadgeStyle"};
1053
1054 stringDrawingState_ = &badgeState;
1055
1056 UIImage *image(MSOldCall(text));
1057
1058 stringDrawingState_ = NULL;
1059 return image;
1060}
1061
1062MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
cc5f5e5d 1063 WBStringDrawingState dayState = {NULL, 2, @""
1ed87fae 1064 // XXX: this is only correct on an iPod dock
19fe3063
JF
1065 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
1066 , @"CalendarIconDayStyle"};
1067
0bd83a3c
JF
1068 WBStringDrawingState skipState = {&dayState,
1069 unsigned(kCFCoreFoundationVersionNumber > 800 ? 16 : 7)
1070 , nil, nil};
8542ae03 1071
0bd83a3c 1072 WBStringDrawingState dateState = {&skipState, 2, @""
19fe3063
JF
1073 , @"CalendarIconDateStyle"};
1074
1075 stringDrawingState_ = &dateState;
1076
1077 UIImage *image(MSOldCall(type));
1078
1079 stringDrawingState_ = NULL;
1080 return image;
1081}
1082
8f0ba4d8
JF
1083MSInstanceMessageHook1(UIImage *, UIStatusBarTimeItemView, contentsImageForStyle, int, style) {
1084 WBStringDrawingState timeState = {NULL, 0, @""
8f0ba4d8
JF
1085 , @"TimeStyle"};
1086
1087 stringDrawingState_ = &timeState;
1088
1089 UIImage *image(MSOldCall(style));
1090
1091 stringDrawingState_ = NULL;
1092 return image;
1093}
1094
0316ebc4 1095MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
4668cd8e
JF
1096 NSBundle *bundle([NSBundle mainBundle]);
1097
e6f0817b
JF
1098 CFLocaleRef locale(CFLocaleCopyCurrent());
1099 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
1100 CFRelease(locale);
1101
1102 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
1103
77d89d52 1104 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
e6f0817b 1105 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
44aa4549 1106 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
e6f0817b
JF
1107 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
1108
1109 CFRelease(now);
1110
1111 CFRelease(formatter);
1112
c79980f5 1113 NSString *datestyle([@""
e6f0817b
JF
1114 "font-family: Helvetica; "
1115 "font-weight: bold; "
e6f0817b
JF
1116 "color: #333333; "
1117 "alpha: 1.0; "
1d3b613f 1118 "" stringByAppendingString:(IsWild_
c79980f5
JF
1119 ? @"font-size: 54px; "
1120 : @"font-size: 39px; "
1121 )]);
e6f0817b 1122
c79980f5 1123 NSString *daystyle([@""
e6f0817b
JF
1124 "font-family: Helvetica; "
1125 "font-weight: bold; "
e6f0817b
JF
1126 "color: white; "
1127 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
1d3b613f 1128 "" stringByAppendingString:(IsWild_
c79980f5
JF
1129 ? @"font-size: 11px; "
1130 : @"font-size: 9px; "
1131 )]);
e6f0817b
JF
1132
1133 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
1134 datestyle = [datestyle stringByAppendingString:style];
1135 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
1136 daystyle = [daystyle stringByAppendingString:style];
1137
0fa37711 1138 CGFloat width([self bounds].size.width);
4668cd8e
JF
1139 float leeway(10);
1140 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
1141 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
e6f0817b 1142
77d89d52 1143 unsigned base0(IsWild_ ? 89 : 70);
c79980f5 1144 if ($GSFontGetUseLegacyFontMetrics())
77d89d52
JF
1145 base0 = base0 + 1;
1146 unsigned base1(IsWild_ ? 18 : 16);
1147
1148 if (Four_) {
1149 ++base0;
1150 ++base1;
1151 }
81decb42 1152
e6f0817b 1153 [(NSString *)date drawAtPoint:CGPointMake(
77d89d52 1154 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
e6f0817b
JF
1155 ) withStyle:datestyle];
1156
1157 [(NSString *)day drawAtPoint:CGPointMake(
77d89d52 1158 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
e6f0817b
JF
1159 ) withStyle:daystyle];
1160
1161 CFRelease(date);
1162 CFRelease(day);
1163}
1164
e079e414
JF
1165// %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
1166void $setBarStyle$_(NSString *name, int &style) {
1167 if (Debug_)
1168 NSLog(@"WB:Debug:%@Style:%d", name, style);
1169 NSNumber *number = nil;
1170 if (number == nil)
1171 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
1172 if (number == nil)
1173 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
1174 if (number != nil) {
d5fb6e01 1175 style = [number intValue];
e079e414
JF
1176 if (Debug_)
1177 NSLog(@"WB:Debug:%@Style=%d", name, style);
1178 }
26c43b47
JF
1179}
1180
e079e414 1181MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
0316ebc4 1182 $setBarStyle$_(@"Toolbar", style);
e079e414 1183 return MSOldCall(style);
95a5777b
JF
1184}
1185
e079e414 1186MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
0316ebc4 1187 $setBarStyle$_(@"NavigationBar", style);
e079e414 1188 return MSOldCall(style);
26c43b47 1189}
e079e414 1190// }}}
26c43b47 1191
0316ebc4 1192MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
2acbe5b8 1193 [[self superview] setBackgroundColor:[UIColor clearColor]];
0316ebc4 1194 _SBButtonBar$didMoveToSuperview(self, sel);
08454e3a 1195}
62b2dbad 1196
0316ebc4
JF
1197MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
1198 [[self superview] setBackgroundColor:[UIColor clearColor]];
1199 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
1200}
1201
4668cd8e 1202static NSArray *Wallpapers_;
1d3b613f 1203static bool Papered_;
77d89d52 1204static bool Docked_;
6de35b7f 1205static bool SMSBackgrounded_;
4668cd8e 1206static NSString *WallpaperFile_;
502d350e
JF
1207static UIImageView *WallpaperImage_;
1208static UIWebDocumentView *WallpaperPage_;
1209static NSURL *WallpaperURL_;
95a5777b 1210
4668cd8e
JF
1211#define _release(object) \
1212 do if (object != nil) { \
1213 [object release]; \
1214 object = nil; \
1215 } while (false)
1216
e079e414 1217static UIImage *$getImage$(NSString *path) {
e079e414
JF
1218 UIImage *image([UIImage imageWithContentsOfFile:path]);
1219
5b21732c 1220 unsigned scale($getScale$(path));
e079e414
JF
1221 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
1222 [image setScale:scale];
1223
1224 return image;
1225}
1226
0db8a084 1227template <typename Original_, typename Modified_>
5e57af81 1228_finline UIImage *WBCacheImage(const Modified_ &modified, const Original_ &original, NSString *key) {
0db8a084
JF
1229 UIImage *image([Images_ objectForKey:key]);
1230 if (image != nil)
1231 return reinterpret_cast<id>(image) == [NSNull null] ? original() : image;
1232 if (NSString *path = modified())
1233 image = $getImage$(path);
1234 [Images_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1235 return image == nil ? original() : image;
1236}
1237
eae989a3
JF
1238static UIImage *$getDefaultDesktopImage$() {
1239 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
1240 return $getImage$(path);
1241 return nil;
1242}
1243
1244MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
1245 return $getDefaultDesktopImage$() ?: MSOldCall();
1246}
1247
1248MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
1249 return $getDefaultDesktopImage$() ?: MSOldCall();
1250}
1251
1252MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
1253 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
1254 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
1255 if (UIImage *image = $getDefaultDesktopImage$()) {
1256 [self setImage:image];
1257 return;
1258 }
1259
1260 break;
1261 }
1262
1263 MSOldCall();
1264}
1265
e079e414
JF
1266// %hook -[SBUIController init] {{{
1267MSInstanceMessageHook0(id, SBUIController, init) {
1268 self = MSOldCall();
d5168fd6
JF
1269 if (self == nil)
1270 return nil;
1271
39271ad2 1272 NSString *paper($getTheme$(Wallpapers_));
ecf154db
JF
1273 if (paper != nil)
1274 paper = [paper stringByDeletingLastPathComponent];
e079e414 1275
0137e6de
JF
1276 if (Debug_)
1277 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
1278
e079e414 1279 if (paper != nil) {
55e82d74 1280 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
1d3b613f
JF
1281 if (&_wallpaperView != NULL) {
1282 [_wallpaperView removeFromSuperview];
1283 [_wallpaperView release];
1284 _wallpaperView = nil;
1285 }
1286 }
1287
44aa4549 1288 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
69550bfb
JF
1289 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
1290
77d89d52 1291 UIView **player;
44aa4549 1292 if (&_contentLayer != NULL)
77d89d52 1293 player = &_contentLayer;
44aa4549 1294 else if (&_contentView != NULL)
77d89d52 1295 player = &_contentView;
44aa4549 1296 else
77d89d52 1297 player = NULL;
77d89d52 1298 UIView *layer(player == NULL ? nil : *player);
44aa4549 1299
55e82d74
JF
1300 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
1301 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
1302 [window setContentView:content];
1303
1304 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
1305 [window setBackgroundColor:[_window backgroundColor]];
1306 [_window setBackgroundColor:[UIColor clearColor]];
1307
1308 [window setLevel:-1000];
1309 [window setHidden:NO];
1d3b613f 1310
77d89d52
JF
1311 /*if (player != NULL)
1312 *player = content;*/
1313
44aa4549
JF
1314 [content setBackgroundColor:[layer backgroundColor]];
1315 [layer setBackgroundColor:[UIColor clearColor]];
69550bfb 1316
1d3b613f
JF
1317 UIView *indirect;
1318 if (!SummerBoard_ || !IsWild_)
1319 indirect = content;
1320 else {
1321 CGRect bounds([content bounds]);
c8fbf228 1322 bounds.origin.y = -30;
1d3b613f
JF
1323 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
1324 [content addSubview:indirect];
1325 [indirect zoomToScale:2.4];
1326 }
1327
4668cd8e
JF
1328 _release(WallpaperFile_);
1329 _release(WallpaperImage_);
1330 _release(WallpaperPage_);
1331 _release(WallpaperURL_);
1332
ecf154db
JF
1333 if (paper != nil) {
1334 NSArray *themes([NSArray arrayWithObject:paper]);
1335
1336 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
d806256e
JF
1337#if UseAVController
1338 NSError *error;
1339
1340 static AVController *controller_(nil);
1341 if (controller_ == nil) {
1342 AVQueue *queue([AVQueue avQueue]);
1343 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1344 }
1345
1346 AVQueue *queue([controller_ queue]);
1347
1d3b613f 1348 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
d806256e
JF
1349 [controller_ setLayer:[video _layer]];
1350
e079e414 1351 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
d806256e
JF
1352 [queue appendItem:item error:&error];
1353
1354 [controller_ play:&error];
1355#elif UseMPMoviePlayerController
e079e414 1356 NSURL *url([NSURL fileURLWithPath:path]);
265e19b2 1357 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
d806256e
JF
1358 controller.movieControlMode = MPMovieControlModeHidden;
1359 [controller play];
1360#else
1d3b613f 1361 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
e079e414 1362 [video setMovieWithPath:path];
4668cd8e 1363 [video setRepeatMode:1];
d806256e 1364 [video setRepeatGap:-1];
4668cd8e 1365 [video playFromBeginning];;
d806256e
JF
1366#endif
1367
1d3b613f 1368 [indirect addSubview:video];
4668cd8e 1369 }
d5fb6e01 1370
b461e3ec 1371 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
e079e414
JF
1372 if (UIImage *image = $getImage$(path)) {
1373 WallpaperFile_ = [path retain];
1374 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1375 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1376 [WallpaperImage_ setAlpha:[number floatValue]];
1377 [indirect addSubview:WallpaperImage_];
1378 }
4668cd8e 1379 }
394d1eb5 1380
b461e3ec 1381 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1d3b613f 1382 CGRect bounds = [indirect bounds];
502d350e 1383
797e4164 1384 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
4668cd8e 1385 [view setAutoresizes:true];
502d350e 1386
4668cd8e 1387 WallpaperPage_ = [view retain];
e079e414 1388 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
394d1eb5 1389
4668cd8e
JF
1390 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1391
4668cd8e 1392 [view setBackgroundColor:[UIColor clearColor]];
1a4ffdf8
JF
1393 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1394 [view setDrawsBackground:NO];
1395 [[view webView] setDrawsBackground:NO];
394d1eb5 1396
1d3b613f 1397 [indirect addSubview:view];
4668cd8e 1398 }
08454e3a 1399 }
d5168fd6 1400
e079e414
JF
1401 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1402 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
5e5c7190
JF
1403 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1404 if ([Manager_ fileExistsAtPath:html]) {
1d3b613f 1405 CGRect bounds = [indirect bounds];
5e5c7190 1406
797e4164 1407 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
5e5c7190
JF
1408 [view setAutoresizes:true];
1409
1410 NSURL *url = [NSURL fileURLWithPath:html];
1411 [view loadRequest:[NSURLRequest requestWithURL:url]];
1412
5e5c7190 1413 [view setBackgroundColor:[UIColor clearColor]];
1a4ffdf8
JF
1414 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1415 [view setDrawsBackground:NO];
1416 [[view webView] setDrawsBackground:NO];
5e5c7190 1417
1d3b613f 1418 [indirect addSubview:view];
5e5c7190
JF
1419 }
1420 }
1421
d5168fd6
JF
1422 return self;
1423}
e079e414 1424// }}}
d5168fd6 1425
9cfe3924 1426MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
502d350e 1427 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
2acbe5b8 1428 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
502d350e 1429
2acbe5b8
JF
1430 if (path != nil && _backgroundView != nil)
1431 path = nil;
502d350e 1432
9cfe3924 1433 _SBAwayView$updateDesktopImage$(self, sel, image);
502d350e
JF
1434
1435 if (path != nil) {
1436 CGRect bounds = [self bounds];
1437
797e4164 1438 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
502d350e
JF
1439 [view setAutoresizes:true];
1440
1441 if (WallpaperPage_ != nil)
1442 [WallpaperPage_ release];
1443 WallpaperPage_ = [view retain];
1444
1445 if (WallpaperURL_ != nil)
1446 [WallpaperURL_ release];
1447 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1448
1449 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1450
1451 [[view webView] setDrawsBackground:false];
2acbe5b8 1452 [view setBackgroundColor:[UIColor clearColor]];
502d350e 1453
2acbe5b8 1454 [self insertSubview:view aboveSubview:_backgroundView];
dd1a5c4b
JF
1455
1456 if ($objc_setAssociatedObject != NULL)
1457 $objc_setAssociatedObject(self, @selector(wb$widgetView), view, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
ca13798d 1458 }
502d350e 1459}
ca13798d 1460
dd1a5c4b
JF
1461MSHook(void, SBAwayView$_addSubview$positioned$relativeTo$, SBAwayView *self, SEL sel, UIView *view, int positioned, UIView *relative) {
1462 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1463 UIView *&_chargingView(MSHookIvar<UIView *>(self, "_chargingView"));
1464 if (&_chargingView != NULL)
1465 if (positioned == -2 && (relative == _backgroundView && _chargingView == nil || relative == _chargingView))
1466 if ($objc_getAssociatedObject != NULL)
1467 if (UIView *widget = $objc_getAssociatedObject(self, @selector(wb$widgetView)))
1468 relative = widget;
1469 return _SBAwayView$_addSubview$positioned$relativeTo$(self, sel, view, positioned, relative);
1470}
1471
95a5777b 1472/*extern "C" CGColorRef CGGStateGetSystemColor(void *);
ca13798d
JF
1473extern "C" CGColorRef CGGStateGetFillColor(void *);
1474extern "C" CGColorRef CGGStateGetStrokeColor(void *);
95a5777b 1475extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
ca13798d 1476
cd6ad593
JF
1477/* WBTimeLabel {{{ */
1478@interface WBTimeLabel : NSProxy {
ca13798d
JF
1479 NSString *time_;
1480 _transient SBStatusBarTimeView *view_;
889cb4f2
JF
1481}
1482
ca13798d 1483- (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
889cb4f2
JF
1484
1485@end
1486
cd6ad593 1487@implementation WBTimeLabel
889cb4f2
JF
1488
1489- (void) dealloc {
ca13798d 1490 [time_ release];
889cb4f2
JF
1491 [super dealloc];
1492}
1493
ca13798d
JF
1494- (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1495 time_ = [time retain];
1496 view_ = view;
889cb4f2
JF
1497 return self;
1498}
1499
44aa4549
JF
1500- (NSString *) description {
1501 return time_;
1502}
1503
ca13798d
JF
1504WBDelegate(time_)
1505
fa006f42 1506- (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
d5fb6e01 1507 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
2acbe5b8 1508 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
d5fb6e01
JF
1509
1510 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1511 "font-family: Helvetica; "
1512 "font-weight: bold; "
1513 "font-size: 14px; "
1514 "color: %@; "
2acbe5b8 1515 "%@", _mode ? @"white" : @"black", custom]];
d5fb6e01
JF
1516
1517 return CGSizeZero;
1518 }
ca13798d
JF
1519
1520 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
889cb4f2
JF
1521}
1522
cd6ad593
JF
1523@end
1524/* }}} */
1525/* WBBadgeLabel {{{ */
1526@interface WBBadgeLabel : NSProxy {
1527 NSString *badge_;
1528}
1529
1530- (id) initWithBadge:(NSString *)badge;
29155933 1531- (NSString *) description;
cd6ad593 1532
ca13798d
JF
1533@end
1534
cd6ad593
JF
1535@implementation WBBadgeLabel
1536
1537- (void) dealloc {
1538 [badge_ release];
1539 [super dealloc];
889cb4f2
JF
1540}
1541
cd6ad593
JF
1542- (id) initWithBadge:(NSString *)badge {
1543 badge_ = [badge retain];
1544 return self;
1545}
1546
29155933
JF
1547- (NSString *) description {
1548 return [badge_ description];
1549}
1550
cd6ad593
JF
1551WBDelegate(badge_)
1552
fa006f42 1553- (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
cd6ad593
JF
1554 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1555 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1556 "font-family: Helvetica; "
1557 "font-weight: bold; "
1558 "font-size: 17px; "
1559 "color: white; "
1560 "%@", custom]];
1561
1562 return CGSizeZero;
1563 }
1564
1565 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1566}
ca13798d
JF
1567
1568@end
cd6ad593
JF
1569/* }}} */
1570
e079e414 1571// IconAlpha {{{
93c020d2 1572MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, CGFloat, alpha) {
8e4d2f42
JF
1573 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1574 alpha = [number floatValue];
e079e414 1575 return MSOldCall(alpha);
8e4d2f42
JF
1576}
1577
93c020d2 1578MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, CGFloat, alpha) {
8e4d2f42
JF
1579 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1580 alpha = [number floatValue];
e079e414 1581 return MSOldCall(alpha);
8e4d2f42
JF
1582}
1583
e079e414
JF
1584MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1585 if ((self = MSOldCall()) != nil) {
8e4d2f42
JF
1586 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1587 // XXX: note: this is overridden above, which is silly
1588 float alpha([number floatValue]);
cbec0f69
JF
1589 if ([self respondsToSelector:@selector(setIconImageAlpha:)])
1590 [self setIconImageAlpha:alpha];
1591 if ([self respondsToSelector:@selector(setIconLabelAlpha:)])
1592 [self setIconLabelAlpha:alpha];
1593 if ([self respondsToSelector:@selector(setAlpha:)])
1594 [self setAlpha:alpha];
8e4d2f42
JF
1595 }
1596 } return self;
1597}
1598
93c020d2 1599MSInstanceMessageHook1(void, SBIcon, setAlpha, CGFloat, alpha) {
b0d0c73f
JF
1600 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1601 alpha = [number floatValue];
e079e414 1602 return MSOldCall(alpha);
b0d0c73f 1603}
e079e414 1604// }}}
b0d0c73f 1605
0316ebc4
JF
1606MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1607 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
2acbe5b8
JF
1608 id &_badge(MSHookIvar<id>(self, "_badge"));
1609 if (_badge != nil)
1610 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1611 _badge = label;
cd6ad593
JF
1612 } return self;
1613}
ca13798d 1614
69550bfb 1615void SBStatusBarController$setStatusBarMode(int &mode) {
95a5777b
JF
1616 if (Debug_)
1617 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
502d350e 1618 if (mode < 100) // 104:hidden 105:glowing
95a5777b
JF
1619 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1620 mode = [number intValue];
d5fb6e01
JF
1621}
1622
69550bfb
JF
1623/*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1624 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1625 SBStatusBarController$setStatusBarMode(mode);
1626 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1627}*/
1628
1629MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
8b94f6b0 1630 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
69550bfb
JF
1631 SBStatusBarController$setStatusBarMode(mode);
1632 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1633}
1634
1635MSHook(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 1636 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
69550bfb 1637 SBStatusBarController$setStatusBarMode(mode);
8b94f6b0 1638 //NSLog(@"mode=%u", mode);
69550bfb
JF
1639 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1640}
1641
1642/*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
d5fb6e01
JF
1643 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1644 mode = [number intValue];
0316ebc4 1645 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
69550bfb 1646}*/
d5fb6e01 1647
0316ebc4
JF
1648MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1649 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
4668cd8e
JF
1650 if (Debug_)
1651 NSLog(@"operatorNameStyle= %@", style);
1652 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1653 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1654 return style;
1655}
1656
0316ebc4 1657MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
4668cd8e
JF
1658 if (Debug_)
1659 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
0316ebc4 1660 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
4668cd8e
JF
1661}
1662
0316ebc4
JF
1663// XXX: replace this with [SBStatusBarTimeView tile]
1664MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
2acbe5b8
JF
1665 id &_time(MSHookIvar<id>(self, "_time"));
1666 if (_time != nil && [_time class] != [WBTimeLabel class])
1667 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
0316ebc4 1668 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
ca13798d
JF
1669}
1670
98fe8d52 1671@interface UIView (WinterBoard)
a8d008e4 1672- (bool) wb$isWBImageView;
198eb03b 1673- (void) wb$logHierarchy;
096012f0 1674- (void) wb$setBackgroundColor:(UIColor *)color;
98fe8d52
JF
1675@end
1676
1677@implementation UIView (WinterBoard)
1678
a8d008e4 1679- (bool) wb$isWBImageView {
98fe8d52
JF
1680 return false;
1681}
1682
198eb03b
JF
1683- (void) wb$logHierarchy {
1684 WBLogHierarchy(self);
1685}
1686
096012f0
JF
1687- (void) wb$setBackgroundColor:(UIColor *)color {
1688 [self setBackgroundColor:color];
1689 for (UIView *child in [self subviews])
1690 [child wb$setBackgroundColor:color];
1691}
1692
98fe8d52
JF
1693@end
1694
a8d008e4
JF
1695@interface WBImageView : UIImageView {
1696}
1697
1698- (bool) wb$isWBImageView;
1699- (void) wb$updateFrame;
98fe8d52
JF
1700@end
1701
a8d008e4 1702@implementation WBImageView
98fe8d52 1703
a8d008e4 1704- (bool) wb$isWBImageView {
98fe8d52
JF
1705 return true;
1706}
1707
a8d008e4
JF
1708- (void) wb$updateFrame {
1709 CGRect frame([self frame]);
1710 frame.origin.y = 0;
1711
1712 for (UIView *view(self); ; ) {
1713 view = [view superview];
1714 if (view == nil)
1715 break;
1716 frame.origin.y -= [view frame].origin.y;
1717 }
1718
1719 [self setFrame:frame];
1720}
1721
98fe8d52
JF
1722@end
1723
af22086e 1724static void SBIconList$updateFrames$(SBIconList *self) {
a8d008e4
JF
1725 NSArray *subviews([self subviews]);
1726 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1727 if (view != nil && [view wb$isWBImageView])
1728 [view wb$updateFrame];
af22086e
JF
1729}
1730
1731MSHook(void, SBIconList$didMoveToSuperview, SBIconList *self, SEL sel) {
1732 SBIconList$updateFrames$(self);
1733 _SBIconList$didMoveToSuperview(self, sel);
1734}
1735
1736MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1737 SBIconList$updateFrames$(self);
a8d008e4
JF
1738 _SBIconList$setFrame$(self, sel, frame);
1739}
1740
fce9dc59
JF
1741static void $addPerPageView$(unsigned i, UIView *list) {
1742 NSString *path($getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]]));
1743 if (path == nil)
1744 return;
1745
1746 NSArray *subviews([list subviews]);
1747
1748 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1749 if (view == nil || ![view wb$isWBImageView]) {
1750 view = [[[WBImageView alloc] init] autorelease];
1751 [list insertSubview:view atIndex:0];
1752 }
98fe8d52 1753
fce9dc59
JF
1754 UIImage *image([UIImage imageWithContentsOfFile:path]);
1755
1756 CGRect frame([view frame]);
1757 frame.size = [image size];
1758 [view setFrame:frame];
1759
1760 [view setImage:image];
1761 [view wb$updateFrame];
1762}
1763
1764static void $addPerPageViews$(NSArray *lists) {
98fe8d52 1765 for (unsigned i(0), e([lists count]); i != e; ++i)
fce9dc59
JF
1766 $addPerPageView$(i, [lists objectAtIndex:i]);
1767}
a8d008e4 1768
fce9dc59
JF
1769MSInstanceMessageHook0(void, SBIconController, updateNumberOfRootIconLists) {
1770 NSArray *&_rootIconLists(MSHookIvar<NSArray *>(self, "_rootIconLists"));
1771 $addPerPageViews$(_rootIconLists);
1772 return MSOldCall();
1773}
1a4ffdf8 1774
fce9dc59
JF
1775MSInstanceMessageHook0(void, SBIconContentView, layoutSubviews) {
1776 MSOldCall();
1a4ffdf8 1777
fce9dc59
JF
1778 if (SBIconController *controller = [$SBIconController sharedInstance]) {
1779 UIView *&_dockContainerView(MSHookIvar<UIView *>(controller, "_dockContainerView"));
1780 if (&_dockContainerView != NULL)
1781 [[_dockContainerView superview] bringSubviewToFront:_dockContainerView];
1782 }
1783}
98fe8d52 1784
fce9dc59
JF
1785MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1786 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1787 $addPerPageViews$([_iconModel iconLists]);
98fe8d52 1788 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
95a5777b
JF
1789}
1790
e542b0ca
JF
1791MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1792 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
cf31d246
JF
1793 if (self != nil)
1794 [self setClipsToBounds:NO];
1795 return self;
1796}
1797
e542b0ca 1798MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
41165a1f
JF
1799 static bool gssc(false);
1800 if (!gssc) {
1801 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1802 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1803 gssc = true;
1804
1805 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1806 [Info_ setObject:[NSNumber numberWithBool:(
1807 !Papered_ ||
1808 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1809 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1810 )] forKey:@"UndockedIconLabels"];
1811 }
1812
2acbe5b8 1813 id &_label(MSHookIvar<id>(self, "_label"));
37351a17 1814 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
95a5777b 1815 docked = true;
e965c1e5 1816
2acbe5b8
JF
1817 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1818 [_label setInDock:docked];
e965c1e5
JF
1819
1820 _SBIconLabel$setInDock$(self, sel, docked);
1821 [self setNeedsDisplay];
889cb4f2
JF
1822}
1823
77d89d52
JF
1824MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1825 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1826}
1827
1828MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1829 _SBDockIconListView$setFrame$(self, sel, frame);
1830}
1831
e079e414
JF
1832// %hook -[NSBundle localizedStringForKey:value:table:] {{{
1833MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
4fa950df
JF
1834 NSString *identifier = [self bundleIdentifier];
1835 NSLocale *locale = [NSLocale currentLocale];
1836 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
2acbe5b8 1837 if (Debug_)
4fa950df
JF
1838 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1839 NSString *file = table == nil ? @"Localizable" : table;
1840 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1841 NSDictionary *strings;
1842 if ((strings = [Strings_ objectForKey:name]) != nil) {
1843 if (static_cast<id>(strings) != [NSNull null]) strings:
1844 if (NSString *value = [strings objectForKey:key])
1845 return value;
1846 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1847 language, file
d9ea6cd5 1848 ], self, false)) {
4fa950df
JF
1849 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1850 [Strings_ setObject:[strings autorelease] forKey:name];
1851 goto strings;
1852 } else goto null;
1853 } else null:
1854 [Strings_ setObject:[NSNull null] forKey:name];
e079e414 1855 return MSOldCall(key, value, table);
4fa950df 1856}
e079e414
JF
1857// }}}
1858// %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1859MSClassHook(WebCoreFrameBridge)
4fa950df 1860
e079e414 1861MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
7ff778ee
JF
1862 if (node == nil)
1863 return CGSizeZero;
1864 void **core(reinterpret_cast<void **>([node _node]));
1865 if (core == NULL || core[6] == NULL)
1866 return CGSizeZero;
e079e414 1867 return MSOldCall(node, width);
7ff778ee 1868}
e079e414 1869// }}}
7ff778ee 1870
b3f846db 1871MSInstanceMessage1(void, SBIconLabel, drawRect, CGRect, rect) {
a3fa54a5
JF
1872 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1873
aa6529f2 1874 int docked;
a3fa54a5
JF
1875 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1876 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
cf31d246 1877
6134e674 1878 NSString *label(MSHookIvar<NSString *>(self, "_label"));
cf31d246
JF
1879
1880 NSString *style = [NSString stringWithFormat:@""
1881 "font-family: Helvetica; "
1882 "font-weight: bold; "
ac1be56e 1883 "color: %@; %@"
1d3b613f 1884 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
ac1be56e
JF
1885 ? @"font-size: 12px; "
1886 : @"font-size: 11px; "
1887 )];
1888
1d3b613f 1889 if (IsWild_)
ac1be56e
JF
1890 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1891 else if (docked)
cf31d246 1892 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
d806256e 1893
cdd7eee4 1894 NSString *custom([Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")]);
cf31d246 1895
cdd7eee4 1896 $drawLabel$(label, [self bounds], style, custom);
889cb4f2
JF
1897}
1898
b3f846db
JF
1899MSInstanceMessage0(CGImageRef, SBIconLabel, buildLabelImage) {
1900 bool docked((MSHookIvar<unsigned>(self, "_inDock") & 0x2) != 0);
1901
6c14ada1 1902 WBStringDrawingState labelState = {NULL, 0, @""
6c14ada1 1903 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
b3f846db
JF
1904
1905 stringDrawingState_ = &labelState;
1906
cc11d828 1907 //NSLog(@"XXX: +");
b3f846db 1908 CGImageRef image(MSOldCall());
cc11d828 1909 //NSLog(@"XXX: -");
b3f846db
JF
1910
1911 stringDrawingState_ = NULL;
1912 return image;
1913}
1914
ff395230
JF
1915static bool wb$inDock(id parameters) {
1916 return [$objc_getAssociatedObject(parameters, @selector(wb$inDock)) boolValue];
1917}
1918
1919MSInstanceMessage0(NSUInteger, SBIconLabelImageParameters, hash) {
1920 return MSOldCall() + (wb$inDock(self) ? 0xdeadbeef : 0xd15ea5e);
1921}
1922
1923MSClassMessage2(id, SBIconView, _labelImageParametersForIcon,location, id, icon, int, location) {
1924 if (id parameters = MSOldCall(icon, location)) {
1925 $objc_setAssociatedObject(parameters, @selector(wb$inDock), [NSNumber numberWithBool:(location == 1)], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1926 return parameters;
1927 } return nil;
1928}
1929
a3dba89f
JF
1930MSInstanceMessage0(id, SBIconView, _labelImageParameters) {
1931 if (id parameters = MSOldCall()) {
1932 int &location(MSHookIvar<int>(self, "_iconLocation"));
1933 if (&location != NULL)
1934 $objc_setAssociatedObject(parameters, @selector(wb$inDock), [NSNumber numberWithBool:(location == 3)], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1935 return parameters;
1936 } return nil;
1937}
1938
ff395230
JF
1939MSClassMessage1(UIImage *, SBIconLabelImage, _drawLabelImageForParameters, id, parameters) {
1940 bool docked(wb$inDock(parameters));
1941
1942 WBStringDrawingState labelState = {NULL, 0, @""
1943 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
1944
1945 stringDrawingState_ = &labelState;
1946
1947 //NSLog(@"XXX: +");
1948 UIImage *image(MSOldCall(parameters));
1949 //NSLog(@"XXX: -");
1950
1951 stringDrawingState_ = NULL;
1952 return image;
1953}
1954
e079e414 1955// ChatKit {{{
6de35b7f
JF
1956MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
1957 if ((self = MSOldCall(frame, delegate)) != nil) {
1958 [self setBackgroundColor:[UIColor clearColor]];
1959 } return self;
1960}
1961
1962MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
1963 return SMSBackgrounded_ ? NO : MSOldCall();
1964}
1965
116c5704
JF
1966MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
1967 [self wb$setBackgroundColor:[UIColor clearColor]];
1968 return MSOldCall();
1969}
1970
e079e414
JF
1971MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
1972 MSOldCall(balloon);
198eb03b
JF
1973 [balloon setBackgroundColor:[UIColor clearColor]];
1974}
1975
e2435eef
JF
1976MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
1977 MSOldCall([UIColor clearColor]);
096012f0 1978 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
e2435eef
JF
1979}
1980
05b58bf3 1981// iOS >= 5.0
a06fac53
JF
1982MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1983 if ((self = MSOldCall(style, reuse)) != nil) {
1984 [self setBackgroundColor:[UIColor clearColor]];
096012f0 1985 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
a06fac53
JF
1986 } return self;
1987}
1988
05b58bf3 1989// iOS << 5.0
e079e414
JF
1990MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1991 if ((self = MSOldCall(style, reuse)) != nil) {
bcb46132 1992 [self setBackgroundColor:[UIColor clearColor]];
198eb03b
JF
1993 [[self contentView] setBackgroundColor:[UIColor clearColor]];
1994 } return self;
1995}
1996
e079e414
JF
1997MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
1998 if ((self = MSOldCall(style, reuse)) != nil) {
198eb03b
JF
1999 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
2000 [_label setBackgroundColor:[UIColor clearColor]];
2001 } return self;
2002}
2003
e079e414
JF
2004MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
2005 MSOldCall(UITableViewCellSeparatorStyleNone);
198eb03b
JF
2006}
2007
e079e414
JF
2008MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
2009 if ((self = MSOldCall(frame, style)) != nil) {
198eb03b
JF
2010 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
2011 } return self;
2012}
2013
e079e414
JF
2014MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
2015 MSOldCall();
e542b0ca 2016
d1c3b33f
JF
2017 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
2018 if (UIImage *image = $getImage$(path)) {
6de35b7f
JF
2019 SMSBackgrounded_ = true;
2020
8b94f6b0 2021 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
4668cd8e 2022 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
8b94f6b0
JF
2023 UIView *table;
2024 if (&_transcriptTable != NULL)
2025 table = _transcriptTable;
2026 else if (&_transcriptLayer != NULL)
2027 table = _transcriptLayer;
2028 else
2029 table = nil;
2030
2031 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
4668cd8e 2032 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
8b94f6b0
JF
2033
2034 if (table == nil)
2035 [placard insertSubview:background atIndex:0];
2036 else {
2037 [table setBackgroundColor:[UIColor clearColor]];
2038 [placard insertSubview:background belowSubview:table];
2039 }
4668cd8e
JF
2040 }
2041}
e079e414 2042// }}}
4668cd8e 2043
0db8a084 2044template <typename Original_>
5e57af81 2045static UIImage *WBCacheImage(NSBundle *bundle, NSString *name, const Original_ &original, NSString *key) {
d6f0973b
JF
2046 if (name == nil)
2047 return original();
2048 NSUInteger period([name rangeOfString:@"."].location);
2049 NSUInteger length([name length]);
2050 if (period == NSNotFound || length < 4 || period > length - 4)
f868c22c 2051 name = [name stringByAppendingString:@".png"];
d6f0973b 2052
5e57af81
JF
2053 return WBCacheImage(
2054 [=](){ return $pathForFile$inBundle$(name, bundle, true); },
2055 [bundle, &original, name](){
d6f0973b
JF
2056 UIImage *image(original());
2057 if (image != nil && UIDebug_) {
2058 NSString *path([@"/tmp/WBImages/" stringByAppendingString:[bundle bundleIdentifier]]);
2059 [Manager_ createDirectoryAtPath:path withIntermediateDirectories:YES attributes:@{NSFilePosixPermissions: @0777} error:NULL];
2060 path = [NSString stringWithFormat:@"%@/%@", path, name];
2061 if (![Manager_ fileExistsAtPath:path])
2062 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
2063 } return image;
5e57af81
JF
2064 },
2065 key);
0f6dbbda
JF
2066}
2067
e079e414 2068// %hook _UIImageWithName() {{{
4df9352e 2069MSHook(UIImage *, _UIImageWithName, NSString *name) {
2c2082b3
JF
2070 if (name == nil)
2071 return nil;
77d89d52 2072 if (Debug_)
0db8a084 2073 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
5e57af81 2074 return WBCacheImage(_UIKitBundle(), name,
0db8a084 2075 [=](){ return __UIImageWithName(name); },
5e57af81 2076 [NSString stringWithFormat:@"I:%@", name]);
95a5777b 2077}
e079e414
JF
2078// }}}
2079// %hook _UIImageWithNameInDomain() {{{
4df9352e 2080MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
95a5777b 2081 if (Debug_)
0db8a084
JF
2082 NSLog(@"WB:Debug: _UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
2083 return WBCacheImage(
0db8a084 2084 [=](){ return $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])); },
5e57af81 2085 [=](){ return __UIImageWithNameInDomain(name, domain); },
0db8a084
JF
2086 [NSString stringWithFormat:@"D:%zu:%@%@", size_t([domain length]), domain, name]);
2087}
2088// }}}
d6f0973b
JF
2089
2090// UISharedArtwork (iOS 6) {{{
2091MSInstanceMessageHook2(UISharedArtwork *, UISharedArtwork, initWithName,inBundle, NSString *, name, NSBundle *, bundle) {
2092 if ((self = MSOldCall(name, bundle)) != nil) {
2093 $objc_setAssociatedObject(self, @selector(wb$bundle), bundle, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
2094 } return self;
2095}
2096
2097MSInstanceMessageHook2(UIImage *, UISharedArtwork, imageNamed,device, NSString *, name, NSInteger, device) {
2098 NSBundle *bundle($objc_getAssociatedObject(self, @selector(wb$bundle)));
0db8a084 2099 if (Debug_)
d6f0973b 2100 NSLog(@"WB:Debug: -[UISharedArtwork(%@) imageNamed:@\"%@\" device:%li]", [bundle bundleIdentifier], name, (long) device);
5e57af81 2101 return WBCacheImage(bundle, name,
d6f0973b 2102 [=](){ return MSOldCall(name, device); },
5e57af81 2103 [NSString stringWithFormat:@"M:%p:%@:%li", self, name, (long) device]);
d6f0973b
JF
2104}
2105// }}}
2106// _UIAssetManager (iOS 7) {{{
2107MSInstanceMessageHook3(_UIAssetManager *, _UIAssetManager, initWithName,inBundle,idiom, NSString *, name, NSBundle *, bundle, NSInteger, idiom) {
2108 if ((self = MSOldCall(name, bundle, idiom)) != nil) {
2109 $objc_setAssociatedObject(self, @selector(wb$bundle), bundle, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
2110 } return self;
2111}
2112
2113MSInstanceMessageHook5(UIImage *, _UIAssetManager, imageNamed,scale,idiom,subtype,cachingOptions, NSString *, name, CGFloat, scale, NSInteger, idiom, NSUInteger, subtype, NSUInteger, caching) {
2114 NSBundle *bundle($objc_getAssociatedObject(self, @selector(wb$bundle)));
2115 if (Debug_)
2116 NSLog(@"WB:Debug: -[_UIAssetManager(%@/%@) imageNamed:@\"%@\" scale:%g idiom:%li subtype:%lu cachingOptions:%lu]",
2117 [bundle bundleIdentifier], [self carFileName],
2118 name, scale, (long) idiom,
2119 (unsigned long) subtype,
2120 (unsigned long) caching
2121 );
2122
2123 if (bundle == _UIKitBundle()) {
2124 NSString *name([self carFileName]);
2125 if (false);
2126 else if ([name isEqualToString:@"UIKit_NewArtwork"])
2127 bundle = [WBBundle bundleWithIdentifier:@"com.apple.uikit.Artwork"];
2128 else if ([name isEqualToString:@"UIKit_OriginalArtwork"])
2129 bundle = [WBBundle bundleWithIdentifier:@"com.apple.uikit.LegacyArtwork"];
2130 }
2131
5e57af81 2132 return WBCacheImage(bundle, name,
d6f0973b 2133 [=](){ return MSOldCall(name, scale, idiom, subtype, caching); },
5e57af81 2134 [NSString stringWithFormat:@"M:%p:%@:%g:%li:%lu", self, name, scale, (long) idiom, (unsigned long) subtype]);
0db8a084
JF
2135}
2136// }}}
d6f0973b
JF
2137// _UIAssetManager (iOS 8) {{{
2138struct SizeClassPair {
2139 NSInteger first;
2140 NSInteger second;
2141};
2142
2143MSInstanceMessageHook7(UIImage *, _UIAssetManager, imageNamed,scale,idiom,subtype,cachingOptions,sizeClassPair,attachCatalogImage, NSString *, name, CGFloat, scale, NSInteger, idiom, NSUInteger, subtype, NSUInteger, caching, SizeClassPair, size, BOOL, attach) {
2144 NSBundle *bundle([self bundle]);
0db8a084 2145 if (Debug_)
d6f0973b
JF
2146 NSLog(@"WB:Debug: -[_UIAssetManager(%@/%@) imageNamed:@\"%@\" scale:%g idiom:%li subtype:%lu cachingOptions:%lu sizeClassPair:[%li %li] attachCatalogImage:%s]",
2147 [bundle bundleIdentifier], [self carFileName],
2148 name, scale, (long) idiom,
2149 (unsigned long) subtype,
2150 (unsigned long) caching,
2151 (long) size.first, (long) size.second,
2152 attach ? "YES" : "NO"
2153 );
5e57af81 2154 return WBCacheImage(bundle, name,
d6f0973b 2155 [=](){ return MSOldCall(name, scale, idiom, subtype, caching, size, attach); },
5e57af81 2156 [NSString stringWithFormat:@"M:%p:%@:%g:%li:%lu:%li:%li:%c", self, name, scale, (long) idiom, (unsigned long) subtype, (long) size.first, (long) size.second, attach ? 'Y' : 'N']);
95a5777b 2157}
e079e414 2158// }}}
95a5777b 2159
e079e414 2160// %hook GSFontCreateWithName() {{{
d806256e 2161MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
9c64bab2
JF
2162 if (Debug_)
2163 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
d806256e
JF
2164 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
2165 name = [font UTF8String];
bae02419
JF
2166 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
2167 // size *= [scale floatValue];
d806256e
JF
2168 return _GSFontCreateWithName(name, traits, size);
2169}
e079e414 2170// }}}
d806256e 2171
95a5777b 2172#define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
95a5777b 2173
33f91d17 2174static bool GetFileNameForThisAction$(bool value, unsigned long a0, char *a1, unsigned long a2, bool &a3) {
95a5777b 2175 if (Debug_)
fdac1738 2176 NSLog(@"WB:Debug:GetFileNameForThisAction(%lu, %s, %lu, %u) = %u", a0, value ? a1 : NULL, a2, a3, value);
95a5777b
JF
2177
2178 if (value) {
2179 NSString *path = [NSString stringWithUTF8String:a1];
2180 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
2181 NSString *file = [path substringFromIndex:31];
e079e414 2182 for (NSString *theme in Themes_) {
95a5777b
JF
2183 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
2184 if ([Manager_ fileExistsAtPath:path]) {
2185 strcpy(a1, [path UTF8String]);
57b2be4c 2186 break;
95a5777b
JF
2187 }
2188 }
2189 }
2190 }
2191 return value;
2192}
2193
33f91d17
JF
2194MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a3) {
2195 bool value(__Z24GetFileNameForThisActionmPcRb(a0, a1, a3));
2196 return GetFileNameForThisAction$(value, a0, a1, 0, a3);
2197}
2198
ffae0a2f
JF
2199#ifdef __LP64__
2200MSHook(bool, _Z24GetFileNameForThisActionjPcjRb, unsigned int a0, char *a1, unsigned int a2, bool &a3) {
2201 bool value(__Z24GetFileNameForThisActionjPcjRb(a0, a1, a2, a3));
2202 return GetFileNameForThisAction$(value, a0, a1, a2, a3);
2203}
2204#else
33f91d17
JF
2205MSHook(bool, _Z24GetFileNameForThisActionmPcmRb, unsigned long a0, char *a1, unsigned long a2, bool &a3) {
2206 bool value(__Z24GetFileNameForThisActionmPcmRb(a0, a1, a2, a3));
2207 return GetFileNameForThisAction$(value, a0, a1, a2, a3);
2208}
ffae0a2f 2209#endif
33f91d17 2210
95a5777b
JF
2211static void ChangeWallpaper(
2212 CFNotificationCenterRef center,
2213 void *observer,
2214 CFStringRef name,
2215 const void *object,
2216 CFDictionaryRef info
2217) {
2218 if (Debug_)
2219 NSLog(@"WB:Debug:ChangeWallpaper!");
502d350e 2220
95a5777b 2221 UIImage *image;
4668cd8e 2222 if (WallpaperFile_ != nil) {
4df9352e 2223 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
95a5777b
JF
2224 if (image != nil)
2225 image = [image autorelease];
2226 } else image = nil;
502d350e
JF
2227
2228 if (WallpaperImage_ != nil)
2229 [WallpaperImage_ setImage:image];
2230 if (WallpaperPage_ != nil)
2231 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
2232
95a5777b 2233}
394d1eb5 2234
661f31ba 2235MSHook(NSArray *, CPBitmapCreateImagesFromPath, NSString *path, CFTypeRef *names, void *arg2, void *arg3) {
01679825 2236 NSArray *images(_CPBitmapCreateImagesFromPath(path, names, arg2, arg3));
661f31ba
JF
2237 if (images == nil)
2238 return nil;
2239 if (*names == nil)
2240 return images;
2241
2242 NSBundle *bundle([NSBundle wb$bundleWithFile:path]);
2243 if (bundle == nil)
2244 return images;
2245
2246 NSString *file([path stringByResolvingSymlinksInPath]);
2247 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
2248 // XXX: why do I care about this?
2249 if (![file hasPrefix:prefix])
2250 return images;
2251
2252 NSMutableArray *copy([images mutableCopy]);
2253 [images release];
2254 images = copy;
2255
2256 NSDictionary *indexes;
2257 NSEnumerator *enumerator;
2258
2259 if (CFGetTypeID((CFTypeRef) *names) == CFDictionaryGetTypeID()) {
2260 indexes = (NSDictionary *) *names;
2261 enumerator = [indexes keyEnumerator];
2262 } else {
2263 indexes = nil;
2264 enumerator = [(NSArray *) *names objectEnumerator];
2265 }
2266
2267 for (NSUInteger index(0); NSString *name = [enumerator nextObject]; ++index)
2268 if (NSString *themed = $pathForFile$inBundle$([name stringByAppendingString:@".png"], bundle, true)) {
2269 if (indexes != nil)
2270 index = [[indexes objectForKey:name] intValue];
39f1cc10
JF
2271 if (UIImage *image = $getImage$(themed))
2272 [copy replaceObjectAtIndex:index withObject:(id)[image CGImage]];
01679825 2273 }
661f31ba
JF
2274
2275 return images;
01679825
JF
2276}
2277
3869239a
JF
2278MSHook(void, BKSDisplayServicesSetSystemAppExitedImagePath, NSString *path) {
2279 if (NSString *themed = $getTheme$($useScale$([NSArray arrayWithObject:@"SystemAppExited.png"])))
2280 path = themed;
2281 _BKSDisplayServicesSetSystemAppExitedImagePath(path);
2282}
2283
0316ebc4 2284#define WBRename(name, sel, imp) \
fdd97c90 2285 MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp, &_ ## name ## $ ## imp)
e6f0817b 2286
e079e414
JF
2287template <typename Type_>
2288static void msset(Type_ &function, MSImageRef image, const char *name) {
2289 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
2290}
2291
fdac1738
JF
2292#define WBHookSymbol(image, function) \
2293 msset(function, image, "_" #function)
2294
9c64bab2
JF
2295template <typename Type_>
2296static void dlset(Type_ &function, const char *name) {
8b94f6b0 2297 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
9c64bab2
JF
2298}
2299
e079e414
JF
2300// %hook CGImageReadCreateWithFile() {{{
2301MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
2302 if (Debug_)
2303 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
265e19b2 2304 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
e079e414
JF
2305 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
2306 [pool release];
2307 return value;
2308}
008ae666
JF
2309
2310MSHook(void *, CGImageSourceCreateWithFile, NSString *path, NSDictionary *options) {
2311 if (Debug_)
2312 NSLog(@"WB:Debug: CGImageSourceCreateWithFile(%@, %@)", path, options);
2313 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2314 void *value(_CGImageSourceCreateWithFile([path wb$themedPath], options));
2315 [pool release];
2316 return value;
2317}
2318
2319MSHook(void *, CGImageSourceCreateWithURL, NSURL *url, NSDictionary *options) {
2320 if (Debug_)
2321 NSLog(@"WB:Debug: CGImageSourceCreateWithURL(%@, %@)", url, options);
2322 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2323 if ([url isFileURL])
2324 url = [NSURL fileURLWithPath:[[url path] wb$themedPath]];
2325 void *value(_CGImageSourceCreateWithURL(url, options));
2326 [pool release];
2327 return value;
2328}
e079e414 2329// }}}
d5168fd6 2330
32677d9d
JF
2331static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
2332 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
2333 if (style == nil || [style length] == 0)
2334 style = @"font-family: Helvetica; font-size: 12px";
833bf385
JF
2335 //NSLog(@"XXX:drawP(%@ | %@)", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
2336 [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
32677d9d
JF
2337}
2338
6cd8823c
JF
2339static void NSString$drawInRect$withStyle$(NSString *self, SEL _cmd, CGRect rect, NSString *style) {
2340 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
2341 if (style == nil || [style length] == 0)
2342 style = @"font-family: Helvetica; font-size: 12px";
833bf385 2343 //NSLog(@"XXX:drawR(%@ | %@)", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
6cd8823c
JF
2344 return [[WBMarkup sharedMarkup] drawString:self inRect:rect withStyle:style];
2345}
2346
0fa37711 2347static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, CGFloat width) {
32677d9d
JF
2348 if (style == nil || [style length] == 0)
2349 style = @"font-family: Helvetica; font-size: 12px";
833bf385
JF
2350 CGSize size([[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width]);
2351 //NSLog(@"XXX:size(%@ | %@) = [%g %g]", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "], size.width, size.height);
2352 return size;
32677d9d
JF
2353}
2354
e079e414 2355static void SBInitialize() {
e079e414
JF
2356 if (SummerBoard_) {
2357 WBRename(SBApplication, pathForIcon, pathForIcon);
2358 WBRename(SBApplicationIcon, icon, icon);
2359 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
2360 }
81decb42 2361
e079e414
JF
2362 WBRename(SBBookmarkIcon, icon, icon);
2363 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
2364 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
2365 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
2366 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
f64efe8d 2367
e079e414 2368 WBRename(SBWidgetApplicationIcon, icon, icon);
394d1eb5 2369
e079e414
JF
2370 WBRename(SBDockIconListView, setFrame:, setFrame$);
2371 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
f64efe8d 2372
39004c14 2373 if (kCFCoreFoundationVersionNumber < 600 || SummerBoard_)
b3f846db 2374 WBRename(SBIconLabel, drawRect:, drawRect$);
ff395230 2375 else if (kCFCoreFoundationVersionNumber < 700) {
b3f846db 2376 WBRename(SBIconLabel, buildLabelImage, buildLabelImage);
ff395230
JF
2377 } else {
2378 WBRename(SBIconLabelImageParameters, hash, hash);
2379 WBRename($SBIconView, _labelImageParametersForIcon:location:, _labelImageParametersForIcon$location$);
a3dba89f 2380 WBRename(SBIconView, _labelImageParameters, _labelImageParameters);
ff395230
JF
2381 WBRename($SBIconLabelImage, _drawLabelImageForParameters:, _drawLabelImageForParameters$);
2382 }
b3f846db 2383
e079e414
JF
2384 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
2385 WBRename(SBIconLabel, setInDock:, setInDock$);
95a5777b 2386
af22086e 2387 WBRename(SBIconList, didMoveToSuperview, didMoveToSuperview);
e079e414 2388 WBRename(SBIconList, setFrame:, setFrame$);
d806256e 2389
e079e414
JF
2390 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
2391 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
2392 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
2393 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
2435118f 2394
d1abab1d
JF
2395 if (kCFCoreFoundationVersionNumber < 800) {
2396 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
2397 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
2398 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
2399 }
0316ebc4 2400
e079e414 2401 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
0316ebc4 2402
e079e414 2403 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
dd1a5c4b
JF
2404 if (kCFCoreFoundationVersionNumber >= 700)
2405 WBRename(SBAwayView, _addSubview:positioned:relativeTo:, _addSubview$positioned$relativeTo$);
2406
e079e414
JF
2407 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
2408 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
2409 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
2410 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
2411 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
2412 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
2413 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
2414 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
0316ebc4 2415
e079e414
JF
2416 if (SummerBoard_)
2417 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
d1779636 2418
6fa3da59
JF
2419 if (kCFCoreFoundationVersionNumber >= 800) {
2420 WBRename(NSString, drawInRect:withAttributes:, drawInRect$withAttributes$);
2421 WBRename(NSString, boundingRectWithSize:options:attributes:context:, boundingRectWithSize$options$attributes$context$);
2422 }
e079e414 2423}
e6f0817b 2424
a8a6d935
JF
2425/*MSHook(int, open, const char *path, int oflag, mode_t mode) {
2426 int fd(_open(path, oflag, mode));
2427
2428 static bool no(false);
2429 if (no) return fd;
2430 no = true;
2431
2432 if (strstr(path, "/icon") != NULL)
a02af71f 2433 *reinterpret_cast<void *volatile *>(NULL) = NULL;
a8a6d935
JF
2434
2435 if (fd == -1 && errno == EFAULT)
2436 NSLog(@"open(%p, %#x, %#o) = %d\n", path, oflag, mode, fd);
2437 else
2438 NSLog(@"open(\"%s\", %#x, %#o) = %d\n", path, oflag, mode, fd);
2439
2440 no = false;
2441 return fd;
2442}*/
2443
e079e414 2444MSInitialize {
ff395230
JF
2445 $objc_setAssociatedObject = reinterpret_cast<void (*)(id, void *, id value, objc_AssociationPolicy)>(dlsym(RTLD_DEFAULT, "objc_setAssociatedObject"));
2446 $objc_getAssociatedObject = reinterpret_cast<id (*)(id, void *)>(dlsym(RTLD_DEFAULT, "objc_getAssociatedObject"));
2447 $objc_removeAssociatedObjects = reinterpret_cast<void (*)(id)>(dlsym(RTLD_DEFAULT, "objc_removeAssociatedObjects"));
2448
e079e414 2449 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
e6f0817b 2450
e079e414
JF
2451 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
2452 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
e6f0817b 2453
502d350e 2454 Manager_ = [[NSFileManager defaultManager] retain];
e079e414 2455 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
502d350e 2456
e079e414 2457 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
26c43b47 2458
a24ad1a6
JF
2459 // Initialize IsWild_ {{{
2460 size_t size;
2461 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
2462 char *machine = new char[size];
2463
2464 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
2465 perror("sysctlbyname(\"hw.machine\", ?)");
2466 delete [] machine;
2467 machine = NULL;
2468 }
2469
2470 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
2471 // }}}
e079e414 2472 // Load Settings.plist {{{
265e19b2 2473 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
e1bbeca7
JF
2474 if (kCFCoreFoundationVersionNumber >= 1000)
2475 SummerBoard_ = false;
2476 else if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
265e19b2 2477 SummerBoard_ = [value boolValue];
d236b808
JF
2478 else
2479 SummerBoard_ = true;
2480
265e19b2
JF
2481 if (NSNumber *value = [settings objectForKey:@"Debug"])
2482 Debug_ = [value boolValue];
8e699a82
JF
2483 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
2484 UIDebug_ = [value boolValue];
62b2dbad 2485
265e19b2 2486 NSArray *themes([settings objectForKey:@"Themes"]);
d5fb6e01
JF
2487 if (themes == nil)
2488 if (NSString *theme = [settings objectForKey:@"Theme"])
2489 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
2490 theme, @"Name",
95a5777b 2491 [NSNumber numberWithBool:true], @"Active",
d5fb6e01 2492 nil]];
265e19b2 2493
d5fb6e01
JF
2494 if (themes != nil)
2495 for (NSDictionary *theme in themes) {
265e19b2 2496 NSNumber *active([theme objectForKey:@"Active"]);
d5fb6e01
JF
2497 if (![active boolValue])
2498 continue;
26c43b47 2499
265e19b2 2500 NSString *name([theme objectForKey:@"Name"]);
d5fb6e01
JF
2501 if (name == nil)
2502 continue;
2503
95a5777b 2504 #define testForTheme(format...) \
fdac1738 2505 { \
95a5777b
JF
2506 NSString *path = [NSString stringWithFormat:format]; \
2507 if ([Manager_ fileExistsAtPath:path]) { \
e079e414 2508 [Themes_ addObject:path]; \
95a5777b
JF
2509 continue; \
2510 } \
d5fb6e01 2511 }
d5fb6e01 2512
95a5777b
JF
2513 testForTheme(@"/Library/Themes/%@.theme", name)
2514 testForTheme(@"/Library/Themes/%@", name)
2515 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
265e19b2 2516
d5fb6e01 2517 }
26c43b47 2518 }
e079e414
JF
2519 // }}}
2520 // Merge Info.plist {{{
d5fb6e01
JF
2521 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2522
e079e414 2523 for (NSString *theme in Themes_)
265e19b2 2524 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
d5fb6e01
JF
2525 for (NSString *key in [info allKeys])
2526 if ([Info_ objectForKey:key] == nil)
2527 [Info_ setObject:[info objectForKey:key] forKey:key];
e079e414 2528 // }}}
95a5777b 2529
01679825
JF
2530 // AppSupport {{{
2531 if (MSImageRef image = MSGetImageByName("/System/Library/PrivateFrameworks/AppSupport.framework/AppSupport")) {
661f31ba 2532 NSArray *(*CPBitmapCreateImagesFromPath)(NSString *, CFTypeRef *, void *, void *);
01679825
JF
2533 msset(CPBitmapCreateImagesFromPath, image, "_CPBitmapCreateImagesFromPath");
2534 MSHookFunction(CPBitmapCreateImagesFromPath, MSHake(CPBitmapCreateImagesFromPath));
2535 }
2536 // }}}
e079e414
JF
2537 // AudioToolbox {{{
2538 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
33f91d17 2539 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long, char *, bool &);
e079e414
JF
2540 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
2541 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
33f91d17 2542
ffae0a2f
JF
2543#ifdef __LP64__
2544 bool (*_Z24GetFileNameForThisActionjPcjRb)(unsigned int, char *, unsigned int, bool &);
2545 msset(_Z24GetFileNameForThisActionjPcjRb, image, "__Z24GetFileNameForThisActionjPcjRb");
ffae0a2f
JF
2546 MSHookFunction(_Z24GetFileNameForThisActionjPcjRb, &$_Z24GetFileNameForThisActionjPcjRb, &__Z24GetFileNameForThisActionjPcjRb);
2547#else
33f91d17
JF
2548 bool (*_Z24GetFileNameForThisActionmPcmRb)(unsigned long, char *, unsigned long, bool &);
2549 msset(_Z24GetFileNameForThisActionmPcmRb, image, "__Z24GetFileNameForThisActionmPcmRb");
2550 MSHookFunction(_Z24GetFileNameForThisActionmPcmRb, &$_Z24GetFileNameForThisActionmPcmRb, &__Z24GetFileNameForThisActionmPcmRb);
ffae0a2f 2551#endif
e079e414
JF
2552 }
2553 // }}}
3869239a
JF
2554 // BackBoardServices {{{
2555 if (MSImageRef image = MSGetImageByName("/System/Library/PrivateFrameworks/BackBoardServices.framework/BackBoardServices")) {
2556 void (*BKSDisplayServicesSetSystemAppExitedImagePath)(NSString *path);
2557 msset(BKSDisplayServicesSetSystemAppExitedImagePath, image, "_BKSDisplayServicesSetSystemAppExitedImagePath");
2558 MSHookFunction(BKSDisplayServicesSetSystemAppExitedImagePath, MSHake(BKSDisplayServicesSetSystemAppExitedImagePath));
2559 }
2560 // }}}
fabdff02
JF
2561 // Foundation {{{
2562 if (true) {
2563 MSHookFunction(CFBundleCopyResourceURL, MSHake(CFBundleCopyResourceURL));
2564 }
2565 // }}}
e079e414
JF
2566 // GraphicsServices {{{
2567 if (true) {
2568 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
2569 }
2570 // }}}
2571 // ImageIO {{{
179b9afb
JF
2572 MSImageRef imageio = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO");
2573 if (imageio == NULL)
2574 imageio = MSGetImageByName("/System/Library/PrivateFrameworks/ImageIO.framework/ImageIO");
2575 if (MSImageRef image = imageio) {
42ac4858
JF
2576 void *(*CGImageReadCreateWithFile)(NSString *, int) = NULL;
2577 if (kCFCoreFoundationVersionNumber > 700) // XXX: iOS 6.x
2578 CGImageReadCreateWithFile = NULL;
2579 else {
2580 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
2581 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
2582 }
008ae666
JF
2583
2584 if (CGImageReadCreateWithFile == NULL) {
2585 void *(*CGImageSourceCreateWithFile)(NSString *, NSDictionary *);
2586 msset(CGImageSourceCreateWithFile, image, "_CGImageSourceCreateWithFile");
2587 MSHookFunction(CGImageSourceCreateWithFile, MSHake(CGImageSourceCreateWithFile));
2588
2589 void *(*CGImageSourceCreateWithURL)(NSURL *, NSDictionary *);
2590 msset(CGImageSourceCreateWithURL, image, "_CGImageSourceCreateWithURL");
2591 MSHookFunction(CGImageSourceCreateWithURL, MSHake(CGImageSourceCreateWithURL));
2592 }
e079e414
JF
2593 }
2594 // }}}
2595 // SpringBoard {{{
2596 if (SpringBoard_) {
240a7a4e 2597 Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@3x.png", @"Wallpaper@3x.jpg", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
41165a1f 2598 Papered_ = $getTheme$(Wallpapers_) != nil;
5d46b7b0 2599 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
8b94f6b0 2600
95a5777b
JF
2601 CFNotificationCenterAddObserver(
2602 CFNotificationCenterGetDarwinNotifyCenter(),
6acfb594 2603 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, CFNotificationSuspensionBehaviorCoalesce
95a5777b 2604 );
62b2dbad 2605
cc46954c 2606 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
265e19b2
JF
2607 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
2608 if (MediaPlayer != nil)
2609 [MediaPlayer load];
2610
2611 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
2612 $MPVideoView = objc_getClass("MPVideoView");
cc46954c 2613 }
2acbe5b8 2614
e079e414 2615 SBInitialize();
2acbe5b8 2616 }
e079e414
JF
2617 // }}}
2618 // UIKit {{{
fdac1738 2619 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/UIKit.framework/UIKit")) {
0fa37711
JF
2620#ifdef __LP64__
2621 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v40@0:8{CGPoint=dd}16@32");
2622 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v56@0:8{CGRect={CGSize=dd}{CGSize=dd}}16@48");
2623 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=dd}32@0:8@16d24");
2624#else
2cb720e9
JF
2625 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
2626 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v28@0:4{CGRect={CGSize=ff}{CGSize=ff}}8@24");
2627 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
0fa37711 2628#endif
2cb720e9 2629
0db8a084 2630 WBHookSymbol(image, _UIKitBundle);
0db8a084 2631
d6f0973b
JF
2632 if (kCFCoreFoundationVersionNumber < 700)
2633 MSHookFunction(_UIImageWithName, MSHake(_UIImageWithName));
0db8a084
JF
2634
2635 WBHookSymbol(image, _UIApplicationImageWithName);
2636 MSHookFunction(_UIApplicationImageWithName, MSHake(_UIApplicationImageWithName));
2637
2638 WBHookSymbol(image, _UIImageWithNameInDomain);
2639 MSHookFunction(_UIImageWithNameInDomain, MSHake(_UIImageWithNameInDomain));
2640
712d0089
JF
2641 SEL includeEmoji(@selector(_legacy_drawAtPoint:forWidth:withFont:lineBreakMode:letterSpacing:includeEmoji:));
2642 if (![@"" respondsToSelector:includeEmoji])
2643 includeEmoji = @selector(drawAtPoint:forWidth:withFont:lineBreakMode:letterSpacing:includeEmoji:);
2644 MSHookMessage($NSString, includeEmoji, MSHake(NSString$drawAtPoint$forWidth$withFont$lineBreakMode$letterSpacing$includeEmoji$));
00182b65
JF
2645
2646 SEL letterSpacing(@selector(_legacy_sizeWithFont:forWidth:lineBreakMode:letterSpacing:));
2647 if (![@"" respondsToSelector:letterSpacing])
2648 letterSpacing = @selector(sizeWithFont:forWidth:lineBreakMode:letterSpacing:);
2649 MSHookMessage($NSString, letterSpacing, MSHake(NSString$sizeWithFont$forWidth$lineBreakMode$letterSpacing$));
2650
2651 SEL sizeWithFont(@selector(_legacy_sizeWithFont:));
2652 if (![@"" respondsToSelector:sizeWithFont])
2653 sizeWithFont = @selector(sizeWithFont:);
2654 MSHookMessage($NSString, sizeWithFont, MSHake(NSString$sizeWithFont$));
e079e414
JF
2655 }
2656 // }}}
77d89d52 2657
a8a6d935
JF
2658 //MSHookFunction(reinterpret_cast<int (*)(const char *, int, mode_t)>(&open), MSHake(open));
2659
d5168fd6
JF
2660 [pool release];
2661}