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