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