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