]> git.saurik.com Git - winterboard.git/blame - Library.mm
Support NSAttributedString for iOS 9 calendar day.
[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
1040 return (CGRect) {{0, 0}, [[self string] sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(color), base, info] forWidth:size.width]};
1041}
1042
fd1c824a 1043MSInstanceMessage4(CGSize, NSString, sizeWithFont,forWidth,lineBreakMode,letterSpacing, UIFont *, font, CGFloat, width, UILineBreakMode, mode, CGFloat, spacing) {
cc11d828
JF
1044 //NSLog(@"XXX: #\"%@\" \"%@\" %g %u %g", self, font, width, mode, spacing);
1045
cc5f5e5d
JF
1046 WBStringDrawingState *state(stringDrawingState_);
1047 if (state == NULL)
b3f846db 1048 return MSOldCall(font, width, mode, spacing);
19fe3063 1049
72bd96ab 1050 if (state->count_ != 0 && --state->count_ == 0)
cc5f5e5d
JF
1051 stringDrawingState_ = state->next_;
1052 if (state->info_ == nil)
b3f846db 1053 return MSOldCall(font, width, mode, spacing);
19fe3063 1054
cc5f5e5d
JF
1055 NSString *info([Info_ objectForKey:state->info_]);
1056 if (info == nil)
b3f846db 1057 return MSOldCall(font, width, mode, spacing);
19fe3063 1058
cc5f5e5d 1059 NSString *base(state->base_ ?: @"");
09eac582 1060 NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
367bcc25 1061 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info] forWidth:width];
19fe3063
JF
1062}
1063
fd1c824a 1064MSInstanceMessage1(CGSize, NSString, sizeWithFont, UIFont *, font) {
cc11d828
JF
1065 //NSLog(@"XXX: ?\"%@\"", self);
1066
cc5f5e5d
JF
1067 WBStringDrawingState *state(stringDrawingState_);
1068 if (state == NULL)
1069 return MSOldCall(font);
1070
72bd96ab 1071 if (state->count_ != 0 && --state->count_ == 0)
cc5f5e5d
JF
1072 stringDrawingState_ = state->next_;
1073 if (state->info_ == nil)
1074 return MSOldCall(font);
1075
1076 NSString *info([Info_ objectForKey:state->info_]);
1077 if (info == nil)
1078 return MSOldCall(font);
1079
1080 NSString *base(state->base_ ?: @"");
367bcc25 1081 return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), base, info] forWidth:65535];
cc5f5e5d
JF
1082}
1083
d1779636
JF
1084MSClassMessageHook2(id, SBIconBadgeView, checkoutAccessoryImagesForIcon,location, id, icon, int, location) {
1085 WBStringDrawingState badgeState = {NULL, 0, @""
1086 , @"BadgeStyle"};
1087
1088 stringDrawingState_ = &badgeState;
1089
1090 id images(MSOldCall(icon, location));
1091
1092 stringDrawingState_ = NULL;
1093 return images;
1094}
1095
c40f4c11
JF
1096MSClassMessageHook2(UIImage *, SBIconAccessoryImage, checkoutAccessoryImageForIcon,location, id, icon, int, location) {
1097 if ([self _imageClassForIcon:icon location:location] != $SBIconBadgeImage)
1098 return MSOldCall(icon, location);
1099
72bd96ab 1100 WBStringDrawingState badgeState = {NULL, 0, @""
c40f4c11
JF
1101 , @"BadgeStyle"};
1102
1103 stringDrawingState_ = &badgeState;
1104
1105 UIImage *image(MSOldCall(icon, location));
1106
1107 stringDrawingState_ = NULL;
1108 return image;
1109}
1110
19fe3063 1111MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) {
72bd96ab 1112 WBStringDrawingState badgeState = {NULL, 0, @""
19fe3063
JF
1113 , @"BadgeStyle"};
1114
1115 stringDrawingState_ = &badgeState;
1116
1117 UIImage *image(MSOldCall(text));
1118
1119 stringDrawingState_ = NULL;
1120 return image;
1121}
1122
1123MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) {
62ab6edb 1124 WBStringDrawingState dayState = {NULL, unsigned(kCFCoreFoundationVersionNumber >= 1200 ? 1 : 2), @""
1ed87fae 1125 // XXX: this is only correct on an iPod dock
19fe3063
JF
1126 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;"
1127 , @"CalendarIconDayStyle"};
1128
62ab6edb
JF
1129 unsigned skips;
1130 if (kCFCoreFoundationVersionNumber < 800)
1131 skips = 7;
1132 else if (kCFCoreFoundationVersionNumber < 1200)
1133 skips = 16;
1134 else
1135 skips = 9;
1136
1137 WBStringDrawingState skipState = {&dayState, skips, nil, nil};
8542ae03 1138
0bd83a3c 1139 WBStringDrawingState dateState = {&skipState, 2, @""
19fe3063
JF
1140 , @"CalendarIconDateStyle"};
1141
1142 stringDrawingState_ = &dateState;
1143
1144 UIImage *image(MSOldCall(type));
1145
1146 stringDrawingState_ = NULL;
1147 return image;
1148}
1149
8f0ba4d8
JF
1150MSInstanceMessageHook1(UIImage *, UIStatusBarTimeItemView, contentsImageForStyle, int, style) {
1151 WBStringDrawingState timeState = {NULL, 0, @""
8f0ba4d8
JF
1152 , @"TimeStyle"};
1153
1154 stringDrawingState_ = &timeState;
1155
1156 UIImage *image(MSOldCall(style));
1157
1158 stringDrawingState_ = NULL;
1159 return image;
1160}
1161
0316ebc4 1162MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) {
4668cd8e
JF
1163 NSBundle *bundle([NSBundle mainBundle]);
1164
e6f0817b
JF
1165 CFLocaleRef locale(CFLocaleCopyCurrent());
1166 CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle));
1167 CFRelease(locale);
1168
1169 CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent()));
1170
77d89d52 1171 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NUMBER_FORMAT" value:@"d" table:@"SpringBoard"]);
e6f0817b 1172 CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
44aa4549 1173 CFDateFormatterSetFormat(formatter, (CFStringRef) [bundle localizedStringForKey:@"CALENDAR_ICON_DAY_NAME_FORMAT" value:@"cccc" table:@"SpringBoard"]);
e6f0817b
JF
1174 CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now));
1175
1176 CFRelease(now);
1177
1178 CFRelease(formatter);
1179
c79980f5 1180 NSString *datestyle([@""
e6f0817b
JF
1181 "font-family: Helvetica; "
1182 "font-weight: bold; "
e6f0817b
JF
1183 "color: #333333; "
1184 "alpha: 1.0; "
1d3b613f 1185 "" stringByAppendingString:(IsWild_
c79980f5
JF
1186 ? @"font-size: 54px; "
1187 : @"font-size: 39px; "
1188 )]);
e6f0817b 1189
c79980f5 1190 NSString *daystyle([@""
e6f0817b
JF
1191 "font-family: Helvetica; "
1192 "font-weight: bold; "
e6f0817b
JF
1193 "color: white; "
1194 "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; "
1d3b613f 1195 "" stringByAppendingString:(IsWild_
c79980f5
JF
1196 ? @"font-size: 11px; "
1197 : @"font-size: 9px; "
1198 )]);
e6f0817b
JF
1199
1200 if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"])
1201 datestyle = [datestyle stringByAppendingString:style];
1202 if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"])
1203 daystyle = [daystyle stringByAppendingString:style];
1204
0fa37711 1205 CGFloat width([self bounds].size.width);
4668cd8e
JF
1206 float leeway(10);
1207 CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:(width + leeway)];
1208 CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:(width + leeway)];
e6f0817b 1209
77d89d52 1210 unsigned base0(IsWild_ ? 89 : 70);
c79980f5 1211 if ($GSFontGetUseLegacyFontMetrics())
77d89d52
JF
1212 base0 = base0 + 1;
1213 unsigned base1(IsWild_ ? 18 : 16);
1214
1215 if (Four_) {
1216 ++base0;
1217 ++base1;
1218 }
81decb42 1219
e6f0817b 1220 [(NSString *)date drawAtPoint:CGPointMake(
77d89d52 1221 (width + 1 - datesize.width) / 2, (base0 - datesize.height) / 2
e6f0817b
JF
1222 ) withStyle:datestyle];
1223
1224 [(NSString *)day drawAtPoint:CGPointMake(
77d89d52 1225 (width + 1 - daysize.width) / 2, (base1 - daysize.height) / 2
e6f0817b
JF
1226 ) withStyle:daystyle];
1227
1228 CFRelease(date);
1229 CFRelease(day);
1230}
1231
e079e414
JF
1232// %hook -[{NavigationBar,Toolbar} setBarStyle:] {{{
1233void $setBarStyle$_(NSString *name, int &style) {
1234 if (Debug_)
1235 NSLog(@"WB:Debug:%@Style:%d", name, style);
1236 NSNumber *number = nil;
1237 if (number == nil)
1238 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
1239 if (number == nil)
1240 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
1241 if (number != nil) {
d5fb6e01 1242 style = [number intValue];
e079e414
JF
1243 if (Debug_)
1244 NSLog(@"WB:Debug:%@Style=%d", name, style);
1245 }
26c43b47
JF
1246}
1247
e079e414 1248MSInstanceMessageHook1(void, UIToolbar, setBarStyle, int, style) {
0316ebc4 1249 $setBarStyle$_(@"Toolbar", style);
e079e414 1250 return MSOldCall(style);
95a5777b
JF
1251}
1252
e079e414 1253MSInstanceMessageHook1(void, UINavigationBar, setBarStyle, int, style) {
0316ebc4 1254 $setBarStyle$_(@"NavigationBar", style);
e079e414 1255 return MSOldCall(style);
26c43b47 1256}
e079e414 1257// }}}
26c43b47 1258
0316ebc4 1259MSHook(void, SBButtonBar$didMoveToSuperview, UIView *self, SEL sel) {
2acbe5b8 1260 [[self superview] setBackgroundColor:[UIColor clearColor]];
0316ebc4 1261 _SBButtonBar$didMoveToSuperview(self, sel);
08454e3a 1262}
62b2dbad 1263
0316ebc4
JF
1264MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) {
1265 [[self superview] setBackgroundColor:[UIColor clearColor]];
1266 _SBStatusBarContentsView$didMoveToSuperview(self, sel);
1267}
1268
4668cd8e 1269static NSArray *Wallpapers_;
1d3b613f 1270static bool Papered_;
77d89d52 1271static bool Docked_;
6de35b7f 1272static bool SMSBackgrounded_;
4668cd8e 1273static NSString *WallpaperFile_;
502d350e
JF
1274static UIImageView *WallpaperImage_;
1275static UIWebDocumentView *WallpaperPage_;
1276static NSURL *WallpaperURL_;
95a5777b 1277
4668cd8e
JF
1278#define _release(object) \
1279 do if (object != nil) { \
1280 [object release]; \
1281 object = nil; \
1282 } while (false)
1283
e079e414 1284static UIImage *$getImage$(NSString *path) {
e079e414
JF
1285 UIImage *image([UIImage imageWithContentsOfFile:path]);
1286
5b21732c 1287 unsigned scale($getScale$(path));
e079e414
JF
1288 if (scale != 1 && [image respondsToSelector:@selector(setScale)])
1289 [image setScale:scale];
1290
1291 return image;
1292}
1293
0db8a084 1294template <typename Original_, typename Modified_>
5e57af81 1295_finline UIImage *WBCacheImage(const Modified_ &modified, const Original_ &original, NSString *key) {
0db8a084
JF
1296 UIImage *image([Images_ objectForKey:key]);
1297 if (image != nil)
1298 return reinterpret_cast<id>(image) == [NSNull null] ? original() : image;
1299 if (NSString *path = modified())
1300 image = $getImage$(path);
1301 [Images_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
1302 return image == nil ? original() : image;
1303}
1304
eae989a3
JF
1305static UIImage *$getDefaultDesktopImage$() {
1306 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])))
1307 return $getImage$(path);
1308 return nil;
1309}
1310
1311MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) {
1312 return $getDefaultDesktopImage$() ?: MSOldCall();
1313}
1314
1315MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) {
1316 return $getDefaultDesktopImage$() ?: MSOldCall();
1317}
1318
1319MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) {
1320 for (UIView *parent([self superview]); parent != nil; parent = [parent superview])
1321 if ([parent isKindOfClass:$SBSlidingAlertDisplay]) {
1322 if (UIImage *image = $getDefaultDesktopImage$()) {
1323 [self setImage:image];
1324 return;
1325 }
1326
1327 break;
1328 }
1329
1330 MSOldCall();
1331}
1332
e079e414
JF
1333// %hook -[SBUIController init] {{{
1334MSInstanceMessageHook0(id, SBUIController, init) {
1335 self = MSOldCall();
d5168fd6
JF
1336 if (self == nil)
1337 return nil;
1338
39271ad2 1339 NSString *paper($getTheme$(Wallpapers_));
ecf154db
JF
1340 if (paper != nil)
1341 paper = [paper stringByDeletingLastPathComponent];
e079e414 1342
0137e6de
JF
1343 if (Debug_)
1344 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
1345
e079e414 1346 if (paper != nil) {
55e82d74 1347 UIImageView *&_wallpaperView(MSHookIvar<UIImageView *>(self, "_wallpaperView"));
1d3b613f
JF
1348 if (&_wallpaperView != NULL) {
1349 [_wallpaperView removeFromSuperview];
1350 [_wallpaperView release];
1351 _wallpaperView = nil;
1352 }
1353 }
1354
44aa4549 1355 UIView *&_contentLayer(MSHookIvar<UIView *>(self, "_contentLayer"));
69550bfb
JF
1356 UIView *&_contentView(MSHookIvar<UIView *>(self, "_contentView"));
1357
77d89d52 1358 UIView **player;
44aa4549 1359 if (&_contentLayer != NULL)
77d89d52 1360 player = &_contentLayer;
44aa4549 1361 else if (&_contentView != NULL)
77d89d52 1362 player = &_contentView;
44aa4549 1363 else
77d89d52 1364 player = NULL;
77d89d52 1365 UIView *layer(player == NULL ? nil : *player);
44aa4549 1366
55e82d74
JF
1367 UIWindow *window([[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]);
1368 UIView *content([[[UIView alloc] initWithFrame:[window frame]] autorelease]);
1369 [window setContentView:content];
1370
1371 UIWindow *&_window(MSHookIvar<UIWindow *>(self, "_window"));
1372 [window setBackgroundColor:[_window backgroundColor]];
1373 [_window setBackgroundColor:[UIColor clearColor]];
1374
1375 [window setLevel:-1000];
1376 [window setHidden:NO];
1d3b613f 1377
77d89d52
JF
1378 /*if (player != NULL)
1379 *player = content;*/
1380
44aa4549
JF
1381 [content setBackgroundColor:[layer backgroundColor]];
1382 [layer setBackgroundColor:[UIColor clearColor]];
69550bfb 1383
1d3b613f
JF
1384 UIView *indirect;
1385 if (!SummerBoard_ || !IsWild_)
1386 indirect = content;
1387 else {
1388 CGRect bounds([content bounds]);
c8fbf228 1389 bounds.origin.y = -30;
1d3b613f
JF
1390 indirect = [[[UIView alloc] initWithFrame:bounds] autorelease];
1391 [content addSubview:indirect];
1392 [indirect zoomToScale:2.4];
1393 }
1394
4668cd8e
JF
1395 _release(WallpaperFile_);
1396 _release(WallpaperImage_);
1397 _release(WallpaperPage_);
1398 _release(WallpaperURL_);
1399
ecf154db
JF
1400 if (paper != nil) {
1401 NSArray *themes([NSArray arrayWithObject:paper]);
1402
1403 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) {
d806256e
JF
1404#if UseAVController
1405 NSError *error;
1406
1407 static AVController *controller_(nil);
1408 if (controller_ == nil) {
1409 AVQueue *queue([AVQueue avQueue]);
1410 controller_ = [[AVController avControllerWithQueue:queue error:&error] retain];
1411 }
1412
1413 AVQueue *queue([controller_ queue]);
1414
1d3b613f 1415 UIView *video([[[UIView alloc] initWithFrame:[indirect bounds]] autorelease]);
d806256e
JF
1416 [controller_ setLayer:[video _layer]];
1417
e079e414 1418 AVItem *item([[[AVItem alloc] initWithPath:path error:&error] autorelease]);
d806256e
JF
1419 [queue appendItem:item error:&error];
1420
1421 [controller_ play:&error];
1422#elif UseMPMoviePlayerController
e079e414 1423 NSURL *url([NSURL fileURLWithPath:path]);
265e19b2 1424 MPMoviePlayerController *controller = [[$MPMoviePlayerController alloc] initWithContentURL:url];
d806256e
JF
1425 controller.movieControlMode = MPMovieControlModeHidden;
1426 [controller play];
1427#else
1d3b613f 1428 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[indirect bounds]] autorelease];
e079e414 1429 [video setMovieWithPath:path];
4668cd8e 1430 [video setRepeatMode:1];
d806256e 1431 [video setRepeatGap:-1];
4668cd8e 1432 [video playFromBeginning];;
d806256e
JF
1433#endif
1434
1d3b613f 1435 [indirect addSubview:video];
4668cd8e 1436 }
d5fb6e01 1437
b461e3ec 1438 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) {
e079e414
JF
1439 if (UIImage *image = $getImage$(path)) {
1440 WallpaperFile_ = [path retain];
1441 WallpaperImage_ = [[UIImageView alloc] initWithImage:image];
1442 if (NSNumber *number = [Info_ objectForKey:@"WallpaperAlpha"])
1443 [WallpaperImage_ setAlpha:[number floatValue]];
1444 [indirect addSubview:WallpaperImage_];
1445 }
4668cd8e 1446 }
394d1eb5 1447
b461e3ec 1448 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) {
1d3b613f 1449 CGRect bounds = [indirect bounds];
502d350e 1450
797e4164 1451 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
4668cd8e 1452 [view setAutoresizes:true];
502d350e 1453
4668cd8e 1454 WallpaperPage_ = [view retain];
e079e414 1455 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
394d1eb5 1456
4668cd8e
JF
1457 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1458
4668cd8e 1459 [view setBackgroundColor:[UIColor clearColor]];
1a4ffdf8
JF
1460 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1461 [view setDrawsBackground:NO];
1462 [[view webView] setDrawsBackground:NO];
394d1eb5 1463
1d3b613f 1464 [indirect addSubview:view];
4668cd8e 1465 }
08454e3a 1466 }
d5168fd6 1467
e079e414
JF
1468 for (size_t i(0), e([Themes_ count]); i != e; ++i) {
1469 NSString *theme = [Themes_ objectAtIndex:(e - i - 1)];
5e5c7190
JF
1470 NSString *html = [theme stringByAppendingPathComponent:@"Widget.html"];
1471 if ([Manager_ fileExistsAtPath:html]) {
1d3b613f 1472 CGRect bounds = [indirect bounds];
5e5c7190 1473
797e4164 1474 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
5e5c7190
JF
1475 [view setAutoresizes:true];
1476
1477 NSURL *url = [NSURL fileURLWithPath:html];
1478 [view loadRequest:[NSURLRequest requestWithURL:url]];
1479
5e5c7190 1480 [view setBackgroundColor:[UIColor clearColor]];
1a4ffdf8
JF
1481 if ([view respondsToSelector:@selector(setDrawsBackground:)])
1482 [view setDrawsBackground:NO];
1483 [[view webView] setDrawsBackground:NO];
5e5c7190 1484
1d3b613f 1485 [indirect addSubview:view];
5e5c7190
JF
1486 }
1487 }
1488
d5168fd6
JF
1489 return self;
1490}
e079e414 1491// }}}
d5168fd6 1492
9cfe3924 1493MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage *image) {
502d350e 1494 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
2acbe5b8 1495 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
502d350e 1496
2acbe5b8
JF
1497 if (path != nil && _backgroundView != nil)
1498 path = nil;
502d350e 1499
9cfe3924 1500 _SBAwayView$updateDesktopImage$(self, sel, image);
502d350e
JF
1501
1502 if (path != nil) {
1503 CGRect bounds = [self bounds];
1504
797e4164 1505 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
502d350e
JF
1506 [view setAutoresizes:true];
1507
1508 if (WallpaperPage_ != nil)
1509 [WallpaperPage_ release];
1510 WallpaperPage_ = [view retain];
1511
1512 if (WallpaperURL_ != nil)
1513 [WallpaperURL_ release];
1514 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
1515
1516 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
1517
1518 [[view webView] setDrawsBackground:false];
2acbe5b8 1519 [view setBackgroundColor:[UIColor clearColor]];
502d350e 1520
2acbe5b8 1521 [self insertSubview:view aboveSubview:_backgroundView];
dd1a5c4b
JF
1522
1523 if ($objc_setAssociatedObject != NULL)
1524 $objc_setAssociatedObject(self, @selector(wb$widgetView), view, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
ca13798d 1525 }
502d350e 1526}
ca13798d 1527
dd1a5c4b
JF
1528MSHook(void, SBAwayView$_addSubview$positioned$relativeTo$, SBAwayView *self, SEL sel, UIView *view, int positioned, UIView *relative) {
1529 UIView *&_backgroundView(MSHookIvar<UIView *>(self, "_backgroundView"));
1530 UIView *&_chargingView(MSHookIvar<UIView *>(self, "_chargingView"));
1531 if (&_chargingView != NULL)
1532 if (positioned == -2 && (relative == _backgroundView && _chargingView == nil || relative == _chargingView))
1533 if ($objc_getAssociatedObject != NULL)
1534 if (UIView *widget = $objc_getAssociatedObject(self, @selector(wb$widgetView)))
1535 relative = widget;
1536 return _SBAwayView$_addSubview$positioned$relativeTo$(self, sel, view, positioned, relative);
1537}
1538
95a5777b 1539/*extern "C" CGColorRef CGGStateGetSystemColor(void *);
ca13798d
JF
1540extern "C" CGColorRef CGGStateGetFillColor(void *);
1541extern "C" CGColorRef CGGStateGetStrokeColor(void *);
95a5777b 1542extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
ca13798d 1543
cd6ad593
JF
1544/* WBTimeLabel {{{ */
1545@interface WBTimeLabel : NSProxy {
ca13798d
JF
1546 NSString *time_;
1547 _transient SBStatusBarTimeView *view_;
889cb4f2
JF
1548}
1549
ca13798d 1550- (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
889cb4f2
JF
1551
1552@end
1553
cd6ad593 1554@implementation WBTimeLabel
889cb4f2
JF
1555
1556- (void) dealloc {
ca13798d 1557 [time_ release];
889cb4f2
JF
1558 [super dealloc];
1559}
1560
ca13798d
JF
1561- (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
1562 time_ = [time retain];
1563 view_ = view;
889cb4f2
JF
1564 return self;
1565}
1566
44aa4549
JF
1567- (NSString *) description {
1568 return time_;
1569}
1570
ca13798d
JF
1571WBDelegate(time_)
1572
fa006f42 1573- (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
d5fb6e01 1574 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
2acbe5b8 1575 BOOL &_mode(MSHookIvar<BOOL>(view_, "_mode"));;
d5fb6e01
JF
1576
1577 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1578 "font-family: Helvetica; "
1579 "font-weight: bold; "
1580 "font-size: 14px; "
1581 "color: %@; "
2acbe5b8 1582 "%@", _mode ? @"white" : @"black", custom]];
d5fb6e01
JF
1583
1584 return CGSizeZero;
1585 }
ca13798d
JF
1586
1587 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
889cb4f2
JF
1588}
1589
cd6ad593
JF
1590@end
1591/* }}} */
1592/* WBBadgeLabel {{{ */
1593@interface WBBadgeLabel : NSProxy {
1594 NSString *badge_;
1595}
1596
1597- (id) initWithBadge:(NSString *)badge;
29155933 1598- (NSString *) description;
cd6ad593 1599
ca13798d
JF
1600@end
1601
cd6ad593
JF
1602@implementation WBBadgeLabel
1603
1604- (void) dealloc {
1605 [badge_ release];
1606 [super dealloc];
889cb4f2
JF
1607}
1608
cd6ad593
JF
1609- (id) initWithBadge:(NSString *)badge {
1610 badge_ = [badge retain];
1611 return self;
1612}
1613
29155933
JF
1614- (NSString *) description {
1615 return [badge_ description];
1616}
1617
cd6ad593
JF
1618WBDelegate(badge_)
1619
fa006f42 1620- (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode {
cd6ad593
JF
1621 if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) {
1622 [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
1623 "font-family: Helvetica; "
1624 "font-weight: bold; "
1625 "font-size: 17px; "
1626 "color: white; "
1627 "%@", custom]];
1628
1629 return CGSizeZero;
1630 }
1631
1632 return [badge_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
1633}
ca13798d
JF
1634
1635@end
cd6ad593
JF
1636/* }}} */
1637
e079e414 1638// IconAlpha {{{
93c020d2 1639MSInstanceMessageHook1(void, SBIcon, setIconImageAlpha, CGFloat, alpha) {
8e4d2f42
JF
1640 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1641 alpha = [number floatValue];
e079e414 1642 return MSOldCall(alpha);
8e4d2f42
JF
1643}
1644
93c020d2 1645MSInstanceMessageHook1(void, SBIcon, setIconLabelAlpha, CGFloat, alpha) {
8e4d2f42
JF
1646 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1647 alpha = [number floatValue];
e079e414 1648 return MSOldCall(alpha);
8e4d2f42
JF
1649}
1650
e079e414
JF
1651MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) {
1652 if ((self = MSOldCall()) != nil) {
8e4d2f42
JF
1653 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) {
1654 // XXX: note: this is overridden above, which is silly
1655 float alpha([number floatValue]);
cbec0f69
JF
1656 if ([self respondsToSelector:@selector(setIconImageAlpha:)])
1657 [self setIconImageAlpha:alpha];
1658 if ([self respondsToSelector:@selector(setIconLabelAlpha:)])
1659 [self setIconLabelAlpha:alpha];
1660 if ([self respondsToSelector:@selector(setAlpha:)])
1661 [self setAlpha:alpha];
8e4d2f42
JF
1662 }
1663 } return self;
1664}
1665
93c020d2 1666MSInstanceMessageHook1(void, SBIcon, setAlpha, CGFloat, alpha) {
b0d0c73f
JF
1667 if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"])
1668 alpha = [number floatValue];
e079e414 1669 return MSOldCall(alpha);
b0d0c73f 1670}
e079e414 1671// }}}
b0d0c73f 1672
0316ebc4
JF
1673MSHook(id, SBIconBadge$initWithBadge$, SBIconBadge *self, SEL sel, NSString *badge) {
1674 if ((self = _SBIconBadge$initWithBadge$(self, sel, badge)) != nil) {
2acbe5b8
JF
1675 id &_badge(MSHookIvar<id>(self, "_badge"));
1676 if (_badge != nil)
1677 if (id label = [[WBBadgeLabel alloc] initWithBadge:[_badge autorelease]])
1678 _badge = label;
cd6ad593
JF
1679 } return self;
1680}
ca13798d 1681
69550bfb 1682void SBStatusBarController$setStatusBarMode(int &mode) {
95a5777b
JF
1683 if (Debug_)
1684 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
502d350e 1685 if (mode < 100) // 104:hidden 105:glowing
95a5777b
JF
1686 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
1687 mode = [number intValue];
d5fb6e01
JF
1688}
1689
69550bfb
JF
1690/*MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, double duration, int animation) {
1691 NSLog(@"mode:%d orientation:%d duration:%f animation:%d", mode, orientation, duration, animation);
1692 SBStatusBarController$setStatusBarMode(mode);
1693 return _SBStatusBarController$setStatusBarMode$orientation$duration$animation$(self, sel, mode, orientation, duration, animation);
1694}*/
1695
1696MSHook(void, SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$, SBStatusBarController *self, SEL sel, int mode, int orientation, float duration, int fenceID, int animation) {
8b94f6b0 1697 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d", mode, orientation, duration, fenceID, animation);
69550bfb
JF
1698 SBStatusBarController$setStatusBarMode(mode);
1699 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(self, sel, mode, orientation, duration, fenceID, animation);
1700}
1701
1702MSHook(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 1703 //NSLog(@"mode:%d orientation:%d duration:%f fenceID:%d animation:%d startTime:%f", mode, orientation, duration, fenceID, animation, startTime);
69550bfb 1704 SBStatusBarController$setStatusBarMode(mode);
8b94f6b0 1705 //NSLog(@"mode=%u", mode);
69550bfb
JF
1706 return _SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$startTime$(self, sel, mode, orientation, duration, fenceID, animation, startTime);
1707}
1708
1709/*MSHook(id, SBStatusBarContentsView$initWithStatusBar$mode$, SBStatusBarContentsView *self, SEL sel, id bar, int mode) {
d5fb6e01
JF
1710 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
1711 mode = [number intValue];
0316ebc4 1712 return _SBStatusBarContentsView$initWithStatusBar$mode$(self, sel, bar, mode);
69550bfb 1713}*/
d5fb6e01 1714
0316ebc4
JF
1715MSHook(NSString *, SBStatusBarOperatorNameView$operatorNameStyle, SBStatusBarOperatorNameView *self, SEL sel) {
1716 NSString *style(_SBStatusBarOperatorNameView$operatorNameStyle(self, sel));
4668cd8e
JF
1717 if (Debug_)
1718 NSLog(@"operatorNameStyle= %@", style);
1719 if (NSString *custom = [Info_ objectForKey:@"OperatorNameStyle"])
1720 style = [NSString stringWithFormat:@"%@; %@", style, custom];
1721 return style;
1722}
1723
0316ebc4 1724MSHook(void, SBStatusBarOperatorNameView$setOperatorName$fullSize$, SBStatusBarOperatorNameView *self, SEL sel, NSString *name, BOOL full) {
4668cd8e
JF
1725 if (Debug_)
1726 NSLog(@"setOperatorName:\"%@\" fullSize:%u", name, full);
0316ebc4 1727 return _SBStatusBarOperatorNameView$setOperatorName$fullSize$(self, sel, name, NO);
4668cd8e
JF
1728}
1729
0316ebc4
JF
1730// XXX: replace this with [SBStatusBarTimeView tile]
1731MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, CGRect rect) {
2acbe5b8
JF
1732 id &_time(MSHookIvar<id>(self, "_time"));
1733 if (_time != nil && [_time class] != [WBTimeLabel class])
1734 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTimeLabel alloc] initWithTime:[_time autorelease] view:self]));
0316ebc4 1735 return _SBStatusBarTimeView$drawRect$(self, sel, rect);
ca13798d
JF
1736}
1737
98fe8d52 1738@interface UIView (WinterBoard)
a8d008e4 1739- (bool) wb$isWBImageView;
198eb03b 1740- (void) wb$logHierarchy;
096012f0 1741- (void) wb$setBackgroundColor:(UIColor *)color;
98fe8d52
JF
1742@end
1743
1744@implementation UIView (WinterBoard)
1745
a8d008e4 1746- (bool) wb$isWBImageView {
98fe8d52
JF
1747 return false;
1748}
1749
198eb03b
JF
1750- (void) wb$logHierarchy {
1751 WBLogHierarchy(self);
1752}
1753
096012f0
JF
1754- (void) wb$setBackgroundColor:(UIColor *)color {
1755 [self setBackgroundColor:color];
1756 for (UIView *child in [self subviews])
1757 [child wb$setBackgroundColor:color];
1758}
1759
98fe8d52
JF
1760@end
1761
a8d008e4
JF
1762@interface WBImageView : UIImageView {
1763}
1764
1765- (bool) wb$isWBImageView;
1766- (void) wb$updateFrame;
98fe8d52
JF
1767@end
1768
a8d008e4 1769@implementation WBImageView
98fe8d52 1770
a8d008e4 1771- (bool) wb$isWBImageView {
98fe8d52
JF
1772 return true;
1773}
1774
a8d008e4
JF
1775- (void) wb$updateFrame {
1776 CGRect frame([self frame]);
1777 frame.origin.y = 0;
1778
1779 for (UIView *view(self); ; ) {
1780 view = [view superview];
1781 if (view == nil)
1782 break;
1783 frame.origin.y -= [view frame].origin.y;
1784 }
1785
1786 [self setFrame:frame];
1787}
1788
98fe8d52
JF
1789@end
1790
af22086e 1791static void SBIconList$updateFrames$(SBIconList *self) {
a8d008e4
JF
1792 NSArray *subviews([self subviews]);
1793 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1794 if (view != nil && [view wb$isWBImageView])
1795 [view wb$updateFrame];
af22086e
JF
1796}
1797
1798MSHook(void, SBIconList$didMoveToSuperview, SBIconList *self, SEL sel) {
1799 SBIconList$updateFrames$(self);
1800 _SBIconList$didMoveToSuperview(self, sel);
1801}
1802
1803MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) {
1804 SBIconList$updateFrames$(self);
a8d008e4
JF
1805 _SBIconList$setFrame$(self, sel, frame);
1806}
1807
fce9dc59
JF
1808static void $addPerPageView$(unsigned i, UIView *list) {
1809 NSString *path($getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]]));
1810 if (path == nil)
1811 return;
1812
1813 NSArray *subviews([list subviews]);
1814
1815 WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]);
1816 if (view == nil || ![view wb$isWBImageView]) {
1817 view = [[[WBImageView alloc] init] autorelease];
1818 [list insertSubview:view atIndex:0];
1819 }
98fe8d52 1820
fce9dc59
JF
1821 UIImage *image([UIImage imageWithContentsOfFile:path]);
1822
1823 CGRect frame([view frame]);
1824 frame.size = [image size];
1825 [view setFrame:frame];
1826
1827 [view setImage:image];
1828 [view wb$updateFrame];
1829}
1830
1831static void $addPerPageViews$(NSArray *lists) {
98fe8d52 1832 for (unsigned i(0), e([lists count]); i != e; ++i)
fce9dc59
JF
1833 $addPerPageView$(i, [lists objectAtIndex:i]);
1834}
a8d008e4 1835
fce9dc59
JF
1836MSInstanceMessageHook0(void, SBIconController, updateNumberOfRootIconLists) {
1837 NSArray *&_rootIconLists(MSHookIvar<NSArray *>(self, "_rootIconLists"));
1838 $addPerPageViews$(_rootIconLists);
1839 return MSOldCall();
1840}
1a4ffdf8 1841
fce9dc59
JF
1842MSInstanceMessageHook0(void, SBIconContentView, layoutSubviews) {
1843 MSOldCall();
1a4ffdf8 1844
fce9dc59
JF
1845 if (SBIconController *controller = [$SBIconController sharedInstance]) {
1846 UIView *&_dockContainerView(MSHookIvar<UIView *>(controller, "_dockContainerView"));
1847 if (&_dockContainerView != NULL)
1848 [[_dockContainerView superview] bringSubviewToFront:_dockContainerView];
1849 }
1850}
98fe8d52 1851
fce9dc59
JF
1852MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) {
1853 SBIconModel *&_iconModel(MSHookIvar<SBIconModel *>(self, "_iconModel"));
1854 $addPerPageViews$([_iconModel iconLists]);
98fe8d52 1855 return _SBIconController$noteNumberOfIconListsChanged(self, sel);
95a5777b
JF
1856}
1857
e542b0ca
JF
1858MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize size, NSString *label) {
1859 self = _SBIconLabel$initWithSize$label$(self, sel, size, label);
cf31d246
JF
1860 if (self != nil)
1861 [self setClipsToBounds:NO];
1862 return self;
1863}
1864
e542b0ca 1865MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) {
41165a1f
JF
1866 static bool gssc(false);
1867 if (!gssc) {
1868 BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast<BOOL (*)(CFStringRef)>(dlsym(RTLD_DEFAULT, "GSSystemHasCapability"));
1869 Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"));
1870 gssc = true;
1871
1872 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1873 [Info_ setObject:[NSNumber numberWithBool:(
1874 !Papered_ ||
1875 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1876 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1877 )] forKey:@"UndockedIconLabels"];
1878 }
1879
2acbe5b8 1880 id &_label(MSHookIvar<id>(self, "_label"));
37351a17 1881 if (![Info_ wb$boolForKey:@"UndockedIconLabels"])
95a5777b 1882 docked = true;
e965c1e5 1883
2acbe5b8
JF
1884 if (_label != nil && [_label respondsToSelector:@selector(setInDock:)])
1885 [_label setInDock:docked];
e965c1e5
JF
1886
1887 _SBIconLabel$setInDock$(self, sel, docked);
1888 [self setNeedsDisplay];
889cb4f2
JF
1889}
1890
77d89d52
JF
1891MSHook(BOOL, SBDockIconListView$shouldShowNewDock, id self, SEL sel) {
1892 return SummerBoard_ && Docked_ ? NO : _SBDockIconListView$shouldShowNewDock(self, sel);
1893}
1894
1895MSHook(void, SBDockIconListView$setFrame$, id self, SEL sel, CGRect frame) {
1896 _SBDockIconListView$setFrame$(self, sel, frame);
1897}
1898
e079e414
JF
1899// %hook -[NSBundle localizedStringForKey:value:table:] {{{
1900MSInstanceMessageHook3(NSString *, NSBundle, localizedStringForKey,value,table, NSString *, key, NSString *, value, NSString *, table) {
4fa950df
JF
1901 NSString *identifier = [self bundleIdentifier];
1902 NSLocale *locale = [NSLocale currentLocale];
1903 NSString *language = [locale objectForKey:NSLocaleLanguageCode];
2acbe5b8 1904 if (Debug_)
4fa950df
JF
1905 NSLog(@"WB:Debug:[NSBundle(%@) localizedStringForKey:\"%@\" value:\"%@\" table:\"%@\"] (%@)", identifier, key, value, table, language);
1906 NSString *file = table == nil ? @"Localizable" : table;
1907 NSString *name = [NSString stringWithFormat:@"%@:%@", identifier, file];
1908 NSDictionary *strings;
1909 if ((strings = [Strings_ objectForKey:name]) != nil) {
1910 if (static_cast<id>(strings) != [NSNull null]) strings:
1911 if (NSString *value = [strings objectForKey:key])
1912 return value;
1913 } else if (NSString *path = $pathForFile$inBundle$([NSString stringWithFormat:@"%@.lproj/%@.strings",
1914 language, file
d9ea6cd5 1915 ], self, false)) {
4fa950df
JF
1916 if ((strings = [[NSDictionary alloc] initWithContentsOfFile:path]) != nil) {
1917 [Strings_ setObject:[strings autorelease] forKey:name];
1918 goto strings;
1919 } else goto null;
1920 } else null:
1921 [Strings_ setObject:[NSNull null] forKey:name];
e079e414 1922 return MSOldCall(key, value, table);
4fa950df 1923}
e079e414
JF
1924// }}}
1925// %hook -[WebCoreFrameBridge renderedSizeOfNode:constrainedToWidth:] {{{
1926MSClassHook(WebCoreFrameBridge)
4fa950df 1927
e079e414 1928MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constrainedToWidth, id, node, float, width) {
7ff778ee
JF
1929 if (node == nil)
1930 return CGSizeZero;
1931 void **core(reinterpret_cast<void **>([node _node]));
1932 if (core == NULL || core[6] == NULL)
1933 return CGSizeZero;
e079e414 1934 return MSOldCall(node, width);
7ff778ee 1935}
e079e414 1936// }}}
7ff778ee 1937
b3f846db 1938MSInstanceMessage1(void, SBIconLabel, drawRect, CGRect, rect) {
a3fa54a5
JF
1939 static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL);
1940
aa6529f2 1941 int docked;
a3fa54a5
JF
1942 Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked));
1943 docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0;
cf31d246 1944
6134e674 1945 NSString *label(MSHookIvar<NSString *>(self, "_label"));
cf31d246
JF
1946
1947 NSString *style = [NSString stringWithFormat:@""
1948 "font-family: Helvetica; "
1949 "font-weight: bold; "
ac1be56e 1950 "color: %@; %@"
1d3b613f 1951 "", (docked || !SummerBoard_ ? @"white" : @"#b3b3b3"), (IsWild_
ac1be56e
JF
1952 ? @"font-size: 12px; "
1953 : @"font-size: 11px; "
1954 )];
1955
1d3b613f 1956 if (IsWild_)
ac1be56e
JF
1957 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px 1px 0px; "];
1958 else if (docked)
cf31d246 1959 style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "];
d806256e 1960
cdd7eee4 1961 NSString *custom([Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")]);
cf31d246 1962
cdd7eee4 1963 $drawLabel$(label, [self bounds], style, custom);
889cb4f2
JF
1964}
1965
b3f846db
JF
1966MSInstanceMessage0(CGImageRef, SBIconLabel, buildLabelImage) {
1967 bool docked((MSHookIvar<unsigned>(self, "_inDock") & 0x2) != 0);
1968
6c14ada1 1969 WBStringDrawingState labelState = {NULL, 0, @""
6c14ada1 1970 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
b3f846db
JF
1971
1972 stringDrawingState_ = &labelState;
1973
cc11d828 1974 //NSLog(@"XXX: +");
b3f846db 1975 CGImageRef image(MSOldCall());
cc11d828 1976 //NSLog(@"XXX: -");
b3f846db
JF
1977
1978 stringDrawingState_ = NULL;
1979 return image;
1980}
1981
ff395230
JF
1982static bool wb$inDock(id parameters) {
1983 return [$objc_getAssociatedObject(parameters, @selector(wb$inDock)) boolValue];
1984}
1985
1986MSInstanceMessage0(NSUInteger, SBIconLabelImageParameters, hash) {
1987 return MSOldCall() + (wb$inDock(self) ? 0xdeadbeef : 0xd15ea5e);
1988}
1989
1990MSClassMessage2(id, SBIconView, _labelImageParametersForIcon,location, id, icon, int, location) {
1991 if (id parameters = MSOldCall(icon, location)) {
1992 $objc_setAssociatedObject(parameters, @selector(wb$inDock), [NSNumber numberWithBool:(location == 1)], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
1993 return parameters;
1994 } return nil;
1995}
1996
a3dba89f
JF
1997MSInstanceMessage0(id, SBIconView, _labelImageParameters) {
1998 if (id parameters = MSOldCall()) {
1999 int &location(MSHookIvar<int>(self, "_iconLocation"));
2000 if (&location != NULL)
2001 $objc_setAssociatedObject(parameters, @selector(wb$inDock), [NSNumber numberWithBool:(location == 3)], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
2002 return parameters;
2003 } return nil;
2004}
2005
ff395230
JF
2006MSClassMessage1(UIImage *, SBIconLabelImage, _drawLabelImageForParameters, id, parameters) {
2007 bool docked(wb$inDock(parameters));
2008
2009 WBStringDrawingState labelState = {NULL, 0, @""
2010 , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
2011
2012 stringDrawingState_ = &labelState;
2013
2014 //NSLog(@"XXX: +");
2015 UIImage *image(MSOldCall(parameters));
2016 //NSLog(@"XXX: -");
2017
2018 stringDrawingState_ = NULL;
2019 return image;
2020}
2021
e079e414 2022// ChatKit {{{
6de35b7f
JF
2023MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) {
2024 if ((self = MSOldCall(frame, delegate)) != nil) {
2025 [self setBackgroundColor:[UIColor clearColor]];
2026 } return self;
2027}
2028
2029MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) {
2030 return SMSBackgrounded_ ? NO : MSOldCall();
2031}
2032
116c5704
JF
2033MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) {
2034 [self wb$setBackgroundColor:[UIColor clearColor]];
2035 return MSOldCall();
2036}
2037
e079e414
JF
2038MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) {
2039 MSOldCall(balloon);
198eb03b
JF
2040 [balloon setBackgroundColor:[UIColor clearColor]];
2041}
2042
e2435eef
JF
2043MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) {
2044 MSOldCall([UIColor clearColor]);
096012f0 2045 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
e2435eef
JF
2046}
2047
05b58bf3 2048// iOS >= 5.0
a06fac53
JF
2049MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
2050 if ((self = MSOldCall(style, reuse)) != nil) {
2051 [self setBackgroundColor:[UIColor clearColor]];
096012f0 2052 [[self contentView] wb$setBackgroundColor:[UIColor clearColor]];
a06fac53
JF
2053 } return self;
2054}
2055
05b58bf3 2056// iOS << 5.0
e079e414
JF
2057MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
2058 if ((self = MSOldCall(style, reuse)) != nil) {
bcb46132 2059 [self setBackgroundColor:[UIColor clearColor]];
198eb03b
JF
2060 [[self contentView] setBackgroundColor:[UIColor clearColor]];
2061 } return self;
2062}
2063
e079e414
JF
2064MSInstanceMessageHook2(id, CKTimestampView, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
2065 if ((self = MSOldCall(style, reuse)) != nil) {
198eb03b
JF
2066 UILabel *&_label(MSHookIvar<UILabel *>(self, "_label"));
2067 [_label setBackgroundColor:[UIColor clearColor]];
2068 } return self;
2069}
2070
e079e414
JF
2071MSInstanceMessageHook1(void, CKTranscriptTableView, setSeparatorStyle, int, style) {
2072 MSOldCall(UITableViewCellSeparatorStyleNone);
198eb03b
JF
2073}
2074
e079e414
JF
2075MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, frame, int, style) {
2076 if ((self = MSOldCall(frame, style)) != nil) {
198eb03b
JF
2077 [self setSeparatorStyle:UITableViewCellSeparatorStyleNone];
2078 } return self;
2079}
2080
e079e414
JF
2081MSInstanceMessageHook0(void, CKTranscriptController, loadView) {
2082 MSOldCall();
e542b0ca 2083
d1c3b33f
JF
2084 if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])))
2085 if (UIImage *image = $getImage$(path)) {
6de35b7f
JF
2086 SMSBackgrounded_ = true;
2087
8b94f6b0 2088 UIView *&_transcriptTable(MSHookIvar<UIView *>(self, "_transcriptTable"));
4668cd8e 2089 UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
8b94f6b0
JF
2090 UIView *table;
2091 if (&_transcriptTable != NULL)
2092 table = _transcriptTable;
2093 else if (&_transcriptLayer != NULL)
2094 table = _transcriptLayer;
2095 else
2096 table = nil;
2097
2098 UIView *placard(table != nil ? [table superview] : MSHookIvar<UIView *>(self, "_backPlacard"));
4668cd8e 2099 UIImageView *background([[[UIImageView alloc] initWithImage:image] autorelease]);
8b94f6b0
JF
2100
2101 if (table == nil)
2102 [placard insertSubview:background atIndex:0];
2103 else {
2104 [table setBackgroundColor:[UIColor clearColor]];
2105 [placard insertSubview:background belowSubview:table];
2106 }
4668cd8e
JF
2107 }
2108}
e079e414 2109// }}}
4668cd8e 2110
0db8a084 2111template <typename Original_>
5e57af81 2112static UIImage *WBCacheImage(NSBundle *bundle, NSString *name, const Original_ &original, NSString *key) {
d6f0973b
JF
2113 if (name == nil)
2114 return original();
2115 NSUInteger period([name rangeOfString:@"."].location);
2116 NSUInteger length([name length]);
2117 if (period == NSNotFound || length < 4 || period > length - 4)
f868c22c 2118 name = [name stringByAppendingString:@".png"];
d6f0973b 2119
5e57af81
JF
2120 return WBCacheImage(
2121 [=](){ return $pathForFile$inBundle$(name, bundle, true); },
2122 [bundle, &original, name](){
d6f0973b
JF
2123 UIImage *image(original());
2124 if (image != nil && UIDebug_) {
2125 NSString *path([@"/tmp/WBImages/" stringByAppendingString:[bundle bundleIdentifier]]);
2126 [Manager_ createDirectoryAtPath:path withIntermediateDirectories:YES attributes:@{NSFilePosixPermissions: @0777} error:NULL];
2127 path = [NSString stringWithFormat:@"%@/%@", path, name];
2128 if (![Manager_ fileExistsAtPath:path])
2129 [UIImagePNGRepresentation(image) writeToFile:path atomically:YES];
2130 } return image;
5e57af81
JF
2131 },
2132 key);
0f6dbbda
JF
2133}
2134
e079e414 2135// %hook _UIImageWithName() {{{
4df9352e 2136MSHook(UIImage *, _UIImageWithName, NSString *name) {
2c2082b3
JF
2137 if (name == nil)
2138 return nil;
77d89d52 2139 if (Debug_)
0db8a084 2140 NSLog(@"WB:Debug: _UIImageWithName(\"%@\")", name);
5e57af81 2141 return WBCacheImage(_UIKitBundle(), name,
0db8a084 2142 [=](){ return __UIImageWithName(name); },
5e57af81 2143 [NSString stringWithFormat:@"I:%@", name]);
95a5777b 2144}
e079e414
JF
2145// }}}
2146// %hook _UIImageWithNameInDomain() {{{
4df9352e 2147MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) {
95a5777b 2148 if (Debug_)
0db8a084
JF
2149 NSLog(@"WB:Debug: _UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain);
2150 return WBCacheImage(
0db8a084 2151 [=](){ return $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])); },
5e57af81 2152 [=](){ return __UIImageWithNameInDomain(name, domain); },
0db8a084
JF
2153 [NSString stringWithFormat:@"D:%zu:%@%@", size_t([domain length]), domain, name]);
2154}
2155// }}}
d6f0973b
JF
2156
2157// UISharedArtwork (iOS 6) {{{
2158MSInstanceMessageHook2(UISharedArtwork *, UISharedArtwork, initWithName,inBundle, NSString *, name, NSBundle *, bundle) {
2159 if ((self = MSOldCall(name, bundle)) != nil) {
2160 $objc_setAssociatedObject(self, @selector(wb$bundle), bundle, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
2161 } return self;
2162}
2163
2164MSInstanceMessageHook2(UIImage *, UISharedArtwork, imageNamed,device, NSString *, name, NSInteger, device) {
2165 NSBundle *bundle($objc_getAssociatedObject(self, @selector(wb$bundle)));
0db8a084 2166 if (Debug_)
d6f0973b 2167 NSLog(@"WB:Debug: -[UISharedArtwork(%@) imageNamed:@\"%@\" device:%li]", [bundle bundleIdentifier], name, (long) device);
5e57af81 2168 return WBCacheImage(bundle, name,
d6f0973b 2169 [=](){ return MSOldCall(name, device); },
5e57af81 2170 [NSString stringWithFormat:@"M:%p:%@:%li", self, name, (long) device]);
d6f0973b
JF
2171}
2172// }}}
2173// _UIAssetManager (iOS 7) {{{
2174MSInstanceMessageHook3(_UIAssetManager *, _UIAssetManager, initWithName,inBundle,idiom, NSString *, name, NSBundle *, bundle, NSInteger, idiom) {
2175 if ((self = MSOldCall(name, bundle, idiom)) != nil) {
2176 $objc_setAssociatedObject(self, @selector(wb$bundle), bundle, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
2177 } return self;
2178}
2179
2180MSInstanceMessageHook5(UIImage *, _UIAssetManager, imageNamed,scale,idiom,subtype,cachingOptions, NSString *, name, CGFloat, scale, NSInteger, idiom, NSUInteger, subtype, NSUInteger, caching) {
2181 NSBundle *bundle($objc_getAssociatedObject(self, @selector(wb$bundle)));
2182 if (Debug_)
2183 NSLog(@"WB:Debug: -[_UIAssetManager(%@/%@) imageNamed:@\"%@\" scale:%g idiom:%li subtype:%lu cachingOptions:%lu]",
2184 [bundle bundleIdentifier], [self carFileName],
2185 name, scale, (long) idiom,
2186 (unsigned long) subtype,
2187 (unsigned long) caching
2188 );
2189
2190 if (bundle == _UIKitBundle()) {
2191 NSString *name([self carFileName]);
2192 if (false);
2193 else if ([name isEqualToString:@"UIKit_NewArtwork"])
2194 bundle = [WBBundle bundleWithIdentifier:@"com.apple.uikit.Artwork"];
2195 else if ([name isEqualToString:@"UIKit_OriginalArtwork"])
2196 bundle = [WBBundle bundleWithIdentifier:@"com.apple.uikit.LegacyArtwork"];
2197 }
2198
5e57af81 2199 return WBCacheImage(bundle, name,
d6f0973b 2200 [=](){ return MSOldCall(name, scale, idiom, subtype, caching); },
5e57af81 2201 [NSString stringWithFormat:@"M:%p:%@:%g:%li:%lu", self, name, scale, (long) idiom, (unsigned long) subtype]);
0db8a084
JF
2202}
2203// }}}
d6f0973b
JF
2204// _UIAssetManager (iOS 8) {{{
2205struct SizeClassPair {
2206 NSInteger first;
2207 NSInteger second;
2208};
2209
2210MSInstanceMessageHook7(UIImage *, _UIAssetManager, imageNamed,scale,idiom,subtype,cachingOptions,sizeClassPair,attachCatalogImage, NSString *, name, CGFloat, scale, NSInteger, idiom, NSUInteger, subtype, NSUInteger, caching, SizeClassPair, size, BOOL, attach) {
2211 NSBundle *bundle([self bundle]);
0db8a084 2212 if (Debug_)
d6f0973b
JF
2213 NSLog(@"WB:Debug: -[_UIAssetManager(%@/%@) imageNamed:@\"%@\" scale:%g idiom:%li subtype:%lu cachingOptions:%lu sizeClassPair:[%li %li] attachCatalogImage:%s]",
2214 [bundle bundleIdentifier], [self carFileName],
2215 name, scale, (long) idiom,
2216 (unsigned long) subtype,
2217 (unsigned long) caching,
2218 (long) size.first, (long) size.second,
2219 attach ? "YES" : "NO"
2220 );
5e57af81 2221 return WBCacheImage(bundle, name,
d6f0973b 2222 [=](){ return MSOldCall(name, scale, idiom, subtype, caching, size, attach); },
5e57af81 2223 [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 2224}
e079e414 2225// }}}
95a5777b 2226
e079e414 2227// %hook GSFontCreateWithName() {{{
d806256e 2228MSHook(GSFontRef, GSFontCreateWithName, const char *name, GSFontSymbolicTraits traits, float size) {
9c64bab2
JF
2229 if (Debug_)
2230 NSLog(@"WB:Debug: GSFontCreateWithName(\"%s\", %f)", name, size);
d806256e
JF
2231 if (NSString *font = [Info_ objectForKey:[NSString stringWithFormat:@"FontName-%s", name]])
2232 name = [font UTF8String];
bae02419
JF
2233 //if (NSString *scale = [Info_ objectForKey:[NSString stringWithFormat:@"FontScale-%s", name]])
2234 // size *= [scale floatValue];
d806256e
JF
2235 return _GSFontCreateWithName(name, traits, size);
2236}
e079e414 2237// }}}
d806256e 2238
95a5777b 2239#define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
95a5777b 2240
33f91d17 2241static bool GetFileNameForThisAction$(bool value, unsigned long a0, char *a1, unsigned long a2, bool &a3) {
95a5777b 2242 if (Debug_)
fdac1738 2243 NSLog(@"WB:Debug:GetFileNameForThisAction(%lu, %s, %lu, %u) = %u", a0, value ? a1 : NULL, a2, a3, value);
95a5777b
JF
2244
2245 if (value) {
2246 NSString *path = [NSString stringWithUTF8String:a1];
2247 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
2248 NSString *file = [path substringFromIndex:31];
e079e414 2249 for (NSString *theme in Themes_) {
95a5777b
JF
2250 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
2251 if ([Manager_ fileExistsAtPath:path]) {
2252 strcpy(a1, [path UTF8String]);
57b2be4c 2253 break;
95a5777b
JF
2254 }
2255 }
2256 }
2257 }
2258 return value;
2259}
2260
33f91d17
JF
2261MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool &a3) {
2262 bool value(__Z24GetFileNameForThisActionmPcRb(a0, a1, a3));
2263 return GetFileNameForThisAction$(value, a0, a1, 0, a3);
2264}
2265
ffae0a2f
JF
2266#ifdef __LP64__
2267MSHook(bool, _Z24GetFileNameForThisActionjPcjRb, unsigned int a0, char *a1, unsigned int a2, bool &a3) {
2268 bool value(__Z24GetFileNameForThisActionjPcjRb(a0, a1, a2, a3));
2269 return GetFileNameForThisAction$(value, a0, a1, a2, a3);
2270}
2271#else
33f91d17
JF
2272MSHook(bool, _Z24GetFileNameForThisActionmPcmRb, unsigned long a0, char *a1, unsigned long a2, bool &a3) {
2273 bool value(__Z24GetFileNameForThisActionmPcmRb(a0, a1, a2, a3));
2274 return GetFileNameForThisAction$(value, a0, a1, a2, a3);
2275}
ffae0a2f 2276#endif
33f91d17 2277
95a5777b
JF
2278static void ChangeWallpaper(
2279 CFNotificationCenterRef center,
2280 void *observer,
2281 CFStringRef name,
2282 const void *object,
2283 CFDictionaryRef info
2284) {
2285 if (Debug_)
2286 NSLog(@"WB:Debug:ChangeWallpaper!");
502d350e 2287
95a5777b 2288 UIImage *image;
4668cd8e 2289 if (WallpaperFile_ != nil) {
4df9352e 2290 image = [[UIImage alloc] initWithContentsOfFile:WallpaperFile_];
95a5777b
JF
2291 if (image != nil)
2292 image = [image autorelease];
2293 } else image = nil;
502d350e
JF
2294
2295 if (WallpaperImage_ != nil)
2296 [WallpaperImage_ setImage:image];
2297 if (WallpaperPage_ != nil)
2298 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
2299
95a5777b 2300}
394d1eb5 2301
661f31ba 2302MSHook(NSArray *, CPBitmapCreateImagesFromPath, NSString *path, CFTypeRef *names, void *arg2, void *arg3) {
01679825 2303 NSArray *images(_CPBitmapCreateImagesFromPath(path, names, arg2, arg3));
661f31ba
JF
2304 if (images == nil)
2305 return nil;
2306 if (*names == nil)
2307 return images;
2308
2309 NSBundle *bundle([NSBundle wb$bundleWithFile:path]);
2310 if (bundle == nil)
2311 return images;
2312
2313 NSString *file([path stringByResolvingSymlinksInPath]);
2314 NSString *prefix([[bundle bundlePath] stringByResolvingSymlinksInPath]);
2315 // XXX: why do I care about this?
2316 if (![file hasPrefix:prefix])
2317 return images;
2318
2319 NSMutableArray *copy([images mutableCopy]);
2320 [images release];
2321 images = copy;
2322
2323 NSDictionary *indexes;
2324 NSEnumerator *enumerator;
2325
2326 if (CFGetTypeID((CFTypeRef) *names) == CFDictionaryGetTypeID()) {
2327 indexes = (NSDictionary *) *names;
2328 enumerator = [indexes keyEnumerator];
2329 } else {
2330 indexes = nil;
2331 enumerator = [(NSArray *) *names objectEnumerator];
2332 }
2333
2334 for (NSUInteger index(0); NSString *name = [enumerator nextObject]; ++index)
2335 if (NSString *themed = $pathForFile$inBundle$([name stringByAppendingString:@".png"], bundle, true)) {
2336 if (indexes != nil)
2337 index = [[indexes objectForKey:name] intValue];
39f1cc10
JF
2338 if (UIImage *image = $getImage$(themed))
2339 [copy replaceObjectAtIndex:index withObject:(id)[image CGImage]];
01679825 2340 }
661f31ba
JF
2341
2342 return images;
01679825
JF
2343}
2344
3869239a
JF
2345MSHook(void, BKSDisplayServicesSetSystemAppExitedImagePath, NSString *path) {
2346 if (NSString *themed = $getTheme$($useScale$([NSArray arrayWithObject:@"SystemAppExited.png"])))
2347 path = themed;
2348 _BKSDisplayServicesSetSystemAppExitedImagePath(path);
2349}
2350
0316ebc4 2351#define WBRename(name, sel, imp) \
fdd97c90 2352 MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp, &_ ## name ## $ ## imp)
e6f0817b 2353
e079e414
JF
2354template <typename Type_>
2355static void msset(Type_ &function, MSImageRef image, const char *name) {
2356 function = reinterpret_cast<Type_>(MSFindSymbol(image, name));
2357}
2358
fdac1738
JF
2359#define WBHookSymbol(image, function) \
2360 msset(function, image, "_" #function)
2361
9c64bab2
JF
2362template <typename Type_>
2363static void dlset(Type_ &function, const char *name) {
8b94f6b0 2364 function = reinterpret_cast<Type_>(dlsym(RTLD_DEFAULT, name));
9c64bab2
JF
2365}
2366
e079e414
JF
2367// %hook CGImageReadCreateWithFile() {{{
2368MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) {
2369 if (Debug_)
2370 NSLog(@"WB:Debug: CGImageReadCreateWithFile(%@, %d)", path, flag);
265e19b2 2371 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
e079e414
JF
2372 void *value(_CGImageReadCreateWithFile([path wb$themedPath], flag));
2373 [pool release];
2374 return value;
2375}
008ae666
JF
2376
2377MSHook(void *, CGImageSourceCreateWithFile, NSString *path, NSDictionary *options) {
2378 if (Debug_)
2379 NSLog(@"WB:Debug: CGImageSourceCreateWithFile(%@, %@)", path, options);
2380 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2381 void *value(_CGImageSourceCreateWithFile([path wb$themedPath], options));
2382 [pool release];
2383 return value;
2384}
2385
2386MSHook(void *, CGImageSourceCreateWithURL, NSURL *url, NSDictionary *options) {
2387 if (Debug_)
2388 NSLog(@"WB:Debug: CGImageSourceCreateWithURL(%@, %@)", url, options);
2389 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
2390 if ([url isFileURL])
2391 url = [NSURL fileURLWithPath:[[url path] wb$themedPath]];
2392 void *value(_CGImageSourceCreateWithURL(url, options));
2393 [pool release];
2394 return value;
2395}
e079e414 2396// }}}
d5168fd6 2397
32677d9d
JF
2398static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) {
2399 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
2400 if (style == nil || [style length] == 0)
2401 style = @"font-family: Helvetica; font-size: 12px";
833bf385
JF
2402 //NSLog(@"XXX:drawP(%@ | %@)", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
2403 [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style];
32677d9d
JF
2404}
2405
6cd8823c
JF
2406static void NSString$drawInRect$withStyle$(NSString *self, SEL _cmd, CGRect rect, NSString *style) {
2407 WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext());
2408 if (style == nil || [style length] == 0)
2409 style = @"font-family: Helvetica; font-size: 12px";
833bf385 2410 //NSLog(@"XXX:drawR(%@ | %@)", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]);
6cd8823c
JF
2411 return [[WBMarkup sharedMarkup] drawString:self inRect:rect withStyle:style];
2412}
2413
0fa37711 2414static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, CGFloat width) {
32677d9d
JF
2415 if (style == nil || [style length] == 0)
2416 style = @"font-family: Helvetica; font-size: 12px";
833bf385
JF
2417 CGSize size([[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width]);
2418 //NSLog(@"XXX:size(%@ | %@) = [%g %g]", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "], size.width, size.height);
2419 return size;
32677d9d
JF
2420}
2421
e079e414 2422static void SBInitialize() {
e079e414
JF
2423 if (SummerBoard_) {
2424 WBRename(SBApplication, pathForIcon, pathForIcon);
2425 WBRename(SBApplicationIcon, icon, icon);
2426 WBRename(SBApplicationIcon, generateIconImage:, generateIconImage$);
2427 }
81decb42 2428
e079e414
JF
2429 WBRename(SBBookmarkIcon, icon, icon);
2430 WBRename(SBButtonBar, didMoveToSuperview, didMoveToSuperview);
2431 WBRename(SBCalendarIconContentsView, drawRect:, drawRect$);
2432 WBRename(SBIconBadge, initWithBadge:, initWithBadge$);
2433 WBRename(SBIconController, noteNumberOfIconListsChanged, noteNumberOfIconListsChanged);
f64efe8d 2434
e079e414 2435 WBRename(SBWidgetApplicationIcon, icon, icon);
394d1eb5 2436
e079e414
JF
2437 WBRename(SBDockIconListView, setFrame:, setFrame$);
2438 MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
f64efe8d 2439
39004c14 2440 if (kCFCoreFoundationVersionNumber < 600 || SummerBoard_)
b3f846db 2441 WBRename(SBIconLabel, drawRect:, drawRect$);
ff395230 2442 else if (kCFCoreFoundationVersionNumber < 700) {
b3f846db 2443 WBRename(SBIconLabel, buildLabelImage, buildLabelImage);
ff395230
JF
2444 } else {
2445 WBRename(SBIconLabelImageParameters, hash, hash);
2446 WBRename($SBIconView, _labelImageParametersForIcon:location:, _labelImageParametersForIcon$location$);
a3dba89f 2447 WBRename(SBIconView, _labelImageParameters, _labelImageParameters);
ff395230
JF
2448 WBRename($SBIconLabelImage, _drawLabelImageForParameters:, _drawLabelImageForParameters$);
2449 }
b3f846db 2450
e079e414
JF
2451 WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
2452 WBRename(SBIconLabel, setInDock:, setInDock$);
95a5777b 2453
af22086e 2454 WBRename(SBIconList, didMoveToSuperview, didMoveToSuperview);
e079e414 2455 WBRename(SBIconList, setFrame:, setFrame$);
d806256e 2456
e079e414
JF
2457 WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$);
2458 WBRename(SBIconModel, cacheImagesForIcon:, cacheImagesForIcon$);
2459 WBRename(SBIconModel, getCachedImagedForIcon:, getCachedImagedForIcon$);
2460 WBRename(SBIconModel, getCachedImagedForIcon:smallIcon:, getCachedImagedForIcon$smallIcon$);
2435118f 2461
d1abab1d
JF
2462 if (kCFCoreFoundationVersionNumber < 800) {
2463 WBRename(SBSearchView, initWithFrame:, initWithFrame$);
2464 WBRename(SBSearchTableViewCell, drawRect:, drawRect$);
2465 WBRename(SBSearchTableViewCell, initWithStyle:reuseIdentifier:, initWithStyle$reuseIdentifier$);
2466 }
0316ebc4 2467
e079e414 2468 //WBRename(SBImageCache, initWithName:forImageWidth:imageHeight:initialCapacity:, initWithName$forImageWidth$imageHeight$initialCapacity$);
0316ebc4 2469
e079e414 2470 WBRename(SBAwayView, updateDesktopImage:, updateDesktopImage$);
dd1a5c4b
JF
2471 if (kCFCoreFoundationVersionNumber >= 700)
2472 WBRename(SBAwayView, _addSubview:positioned:relativeTo:, _addSubview$positioned$relativeTo$);
2473
e079e414
JF
2474 WBRename(SBStatusBarContentsView, didMoveToSuperview, didMoveToSuperview);
2475 //WBRename(SBStatusBarContentsView, initWithStatusBar:mode:, initWithStatusBar$mode$);
2476 //WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:animation:, setStatusBarMode$orientation$duration$animation$);
2477 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:, setStatusBarMode$orientation$duration$fenceID$animation$);
2478 WBRename(SBStatusBarController, setStatusBarMode:orientation:duration:fenceID:animation:startTime:, setStatusBarMode$orientation$duration$fenceID$animation$startTime$);
2479 WBRename(SBStatusBarOperatorNameView, operatorNameStyle, operatorNameStyle);
2480 WBRename(SBStatusBarOperatorNameView, setOperatorName:fullSize:, setOperatorName$fullSize$);
2481 WBRename(SBStatusBarTimeView, drawRect:, drawRect$);
0316ebc4 2482
e079e414
JF
2483 if (SummerBoard_)
2484 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
d1779636 2485
6fa3da59
JF
2486 if (kCFCoreFoundationVersionNumber >= 800) {
2487 WBRename(NSString, drawInRect:withAttributes:, drawInRect$withAttributes$);
2488 WBRename(NSString, boundingRectWithSize:options:attributes:context:, boundingRectWithSize$options$attributes$context$);
2489 }
e079e414 2490}
e6f0817b 2491
a8a6d935
JF
2492/*MSHook(int, open, const char *path, int oflag, mode_t mode) {
2493 int fd(_open(path, oflag, mode));
2494
2495 static bool no(false);
2496 if (no) return fd;
2497 no = true;
2498
2499 if (strstr(path, "/icon") != NULL)
a02af71f 2500 *reinterpret_cast<void *volatile *>(NULL) = NULL;
a8a6d935
JF
2501
2502 if (fd == -1 && errno == EFAULT)
2503 NSLog(@"open(%p, %#x, %#o) = %d\n", path, oflag, mode, fd);
2504 else
2505 NSLog(@"open(\"%s\", %#x, %#o) = %d\n", path, oflag, mode, fd);
2506
2507 no = false;
2508 return fd;
2509}*/
2510
e079e414 2511MSInitialize {
ff395230
JF
2512 $objc_setAssociatedObject = reinterpret_cast<void (*)(id, void *, id value, objc_AssociationPolicy)>(dlsym(RTLD_DEFAULT, "objc_setAssociatedObject"));
2513 $objc_getAssociatedObject = reinterpret_cast<id (*)(id, void *)>(dlsym(RTLD_DEFAULT, "objc_getAssociatedObject"));
2514 $objc_removeAssociatedObjects = reinterpret_cast<void (*)(id)>(dlsym(RTLD_DEFAULT, "objc_removeAssociatedObjects"));
2515
e079e414 2516 NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]);
e6f0817b 2517
e079e414
JF
2518 NSString *identifier([[NSBundle mainBundle] bundleIdentifier]);
2519 SpringBoard_ = [identifier isEqualToString:@"com.apple.springboard"];
e6f0817b 2520
502d350e 2521 Manager_ = [[NSFileManager defaultManager] retain];
e079e414 2522 Themes_ = [[NSMutableArray alloc] initWithCapacity:8];
502d350e 2523
e079e414 2524 dlset(_GSFontGetUseLegacyFontMetrics, "GSFontGetUseLegacyFontMetrics");
26c43b47 2525
a24ad1a6
JF
2526 // Initialize IsWild_ {{{
2527 size_t size;
2528 sysctlbyname("hw.machine", NULL, &size, NULL, 0);
2529 char *machine = new char[size];
2530
2531 if (sysctlbyname("hw.machine", machine, &size, NULL, 0) == -1) {
2532 perror("sysctlbyname(\"hw.machine\", ?)");
2533 delete [] machine;
2534 machine = NULL;
2535 }
2536
2537 IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0;
2538 // }}}
e079e414 2539 // Load Settings.plist {{{
265e19b2 2540 if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
e1bbeca7
JF
2541 if (kCFCoreFoundationVersionNumber >= 1000)
2542 SummerBoard_ = false;
2543 else if (NSNumber *value = [settings objectForKey:@"SummerBoard"])
265e19b2 2544 SummerBoard_ = [value boolValue];
d236b808
JF
2545 else
2546 SummerBoard_ = true;
2547
265e19b2
JF
2548 if (NSNumber *value = [settings objectForKey:@"Debug"])
2549 Debug_ = [value boolValue];
8e699a82
JF
2550 if (NSNumber *value = [settings objectForKey:@"RecordUI"])
2551 UIDebug_ = [value boolValue];
62b2dbad 2552
265e19b2 2553 NSArray *themes([settings objectForKey:@"Themes"]);
d5fb6e01
JF
2554 if (themes == nil)
2555 if (NSString *theme = [settings objectForKey:@"Theme"])
2556 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
2557 theme, @"Name",
95a5777b 2558 [NSNumber numberWithBool:true], @"Active",
d5fb6e01 2559 nil]];
265e19b2 2560
d5fb6e01
JF
2561 if (themes != nil)
2562 for (NSDictionary *theme in themes) {
265e19b2 2563 NSNumber *active([theme objectForKey:@"Active"]);
d5fb6e01
JF
2564 if (![active boolValue])
2565 continue;
26c43b47 2566
265e19b2 2567 NSString *name([theme objectForKey:@"Name"]);
d5fb6e01
JF
2568 if (name == nil)
2569 continue;
2570
95a5777b 2571 #define testForTheme(format...) \
fdac1738 2572 { \
95a5777b
JF
2573 NSString *path = [NSString stringWithFormat:format]; \
2574 if ([Manager_ fileExistsAtPath:path]) { \
e079e414 2575 [Themes_ addObject:path]; \
95a5777b
JF
2576 continue; \
2577 } \
d5fb6e01 2578 }
d5fb6e01 2579
95a5777b
JF
2580 testForTheme(@"/Library/Themes/%@.theme", name)
2581 testForTheme(@"/Library/Themes/%@", name)
2582 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
265e19b2 2583
d5fb6e01 2584 }
26c43b47 2585 }
e079e414
JF
2586 // }}}
2587 // Merge Info.plist {{{
d5fb6e01
JF
2588 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
2589
e079e414 2590 for (NSString *theme in Themes_)
265e19b2 2591 if (NSDictionary *info = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
d5fb6e01
JF
2592 for (NSString *key in [info allKeys])
2593 if ([Info_ objectForKey:key] == nil)
2594 [Info_ setObject:[info objectForKey:key] forKey:key];
e079e414 2595 // }}}
95a5777b 2596
01679825
JF
2597 // AppSupport {{{
2598 if (MSImageRef image = MSGetImageByName("/System/Library/PrivateFrameworks/AppSupport.framework/AppSupport")) {
661f31ba 2599 NSArray *(*CPBitmapCreateImagesFromPath)(NSString *, CFTypeRef *, void *, void *);
01679825
JF
2600 msset(CPBitmapCreateImagesFromPath, image, "_CPBitmapCreateImagesFromPath");
2601 MSHookFunction(CPBitmapCreateImagesFromPath, MSHake(CPBitmapCreateImagesFromPath));
2602 }
2603 // }}}
e079e414
JF
2604 // AudioToolbox {{{
2605 if (MSImageRef image = MSGetImageByName(AudioToolbox)) {
33f91d17 2606 bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long, char *, bool &);
e079e414
JF
2607 msset(_Z24GetFileNameForThisActionmPcRb, image, "__Z24GetFileNameForThisActionmPcRb");
2608 MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &__Z24GetFileNameForThisActionmPcRb);
33f91d17 2609
ffae0a2f
JF
2610#ifdef __LP64__
2611 bool (*_Z24GetFileNameForThisActionjPcjRb)(unsigned int, char *, unsigned int, bool &);
2612 msset(_Z24GetFileNameForThisActionjPcjRb, image, "__Z24GetFileNameForThisActionjPcjRb");
ffae0a2f
JF
2613 MSHookFunction(_Z24GetFileNameForThisActionjPcjRb, &$_Z24GetFileNameForThisActionjPcjRb, &__Z24GetFileNameForThisActionjPcjRb);
2614#else
33f91d17
JF
2615 bool (*_Z24GetFileNameForThisActionmPcmRb)(unsigned long, char *, unsigned long, bool &);
2616 msset(_Z24GetFileNameForThisActionmPcmRb, image, "__Z24GetFileNameForThisActionmPcmRb");
2617 MSHookFunction(_Z24GetFileNameForThisActionmPcmRb, &$_Z24GetFileNameForThisActionmPcmRb, &__Z24GetFileNameForThisActionmPcmRb);
ffae0a2f 2618#endif
e079e414
JF
2619 }
2620 // }}}
3869239a
JF
2621 // BackBoardServices {{{
2622 if (MSImageRef image = MSGetImageByName("/System/Library/PrivateFrameworks/BackBoardServices.framework/BackBoardServices")) {
2623 void (*BKSDisplayServicesSetSystemAppExitedImagePath)(NSString *path);
2624 msset(BKSDisplayServicesSetSystemAppExitedImagePath, image, "_BKSDisplayServicesSetSystemAppExitedImagePath");
2625 MSHookFunction(BKSDisplayServicesSetSystemAppExitedImagePath, MSHake(BKSDisplayServicesSetSystemAppExitedImagePath));
2626 }
2627 // }}}
fabdff02
JF
2628 // Foundation {{{
2629 if (true) {
31c7f1e6 2630 if (![identifier isEqualToString:@"com.apple.backupd"]) // XXX: rethink
fabdff02
JF
2631 MSHookFunction(CFBundleCopyResourceURL, MSHake(CFBundleCopyResourceURL));
2632 }
2633 // }}}
e079e414
JF
2634 // GraphicsServices {{{
2635 if (true) {
2636 MSHookFunction(&GSFontCreateWithName, &$GSFontCreateWithName, &_GSFontCreateWithName);
2637 }
2638 // }}}
2639 // ImageIO {{{
179b9afb
JF
2640 MSImageRef imageio = MSGetImageByName("/System/Library/Frameworks/ImageIO.framework/ImageIO");
2641 if (imageio == NULL)
2642 imageio = MSGetImageByName("/System/Library/PrivateFrameworks/ImageIO.framework/ImageIO");
2643 if (MSImageRef image = imageio) {
42ac4858
JF
2644 void *(*CGImageReadCreateWithFile)(NSString *, int) = NULL;
2645 if (kCFCoreFoundationVersionNumber > 700) // XXX: iOS 6.x
2646 CGImageReadCreateWithFile = NULL;
2647 else {
2648 msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile");
2649 MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile));
2650 }
008ae666
JF
2651
2652 if (CGImageReadCreateWithFile == NULL) {
2653 void *(*CGImageSourceCreateWithFile)(NSString *, NSDictionary *);
2654 msset(CGImageSourceCreateWithFile, image, "_CGImageSourceCreateWithFile");
2655 MSHookFunction(CGImageSourceCreateWithFile, MSHake(CGImageSourceCreateWithFile));
2656
2657 void *(*CGImageSourceCreateWithURL)(NSURL *, NSDictionary *);
2658 msset(CGImageSourceCreateWithURL, image, "_CGImageSourceCreateWithURL");
2659 MSHookFunction(CGImageSourceCreateWithURL, MSHake(CGImageSourceCreateWithURL));
2660 }
e079e414
JF
2661 }
2662 // }}}
2663 // SpringBoard {{{
2664 if (SpringBoard_) {
240a7a4e 2665 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 2666 Papered_ = $getTheme$(Wallpapers_) != nil;
5d46b7b0 2667 Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
8b94f6b0 2668
95a5777b
JF
2669 CFNotificationCenterAddObserver(
2670 CFNotificationCenterGetDarwinNotifyCenter(),
6acfb594 2671 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, CFNotificationSuspensionBehaviorCoalesce
95a5777b 2672 );
62b2dbad 2673
cc46954c 2674 if ($getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"]) != nil) {
265e19b2
JF
2675 NSBundle *MediaPlayer([NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]);
2676 if (MediaPlayer != nil)
2677 [MediaPlayer load];
2678
2679 $MPMoviePlayerController = objc_getClass("MPMoviePlayerController");
2680 $MPVideoView = objc_getClass("MPVideoView");
cc46954c 2681 }
2acbe5b8 2682
e079e414 2683 SBInitialize();
2acbe5b8 2684 }
e079e414
JF
2685 // }}}
2686 // UIKit {{{
fdac1738 2687 if (MSImageRef image = MSGetImageByName("/System/Library/Frameworks/UIKit.framework/UIKit")) {
0fa37711
JF
2688#ifdef __LP64__
2689 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v40@0:8{CGPoint=dd}16@32");
2690 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v56@0:8{CGRect={CGSize=dd}{CGSize=dd}}16@48");
2691 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=dd}32@0:8@16d24");
2692#else
2cb720e9
JF
2693 class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16");
2694 class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v28@0:4{CGRect={CGSize=ff}{CGSize=ff}}8@24");
2695 class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12");
0fa37711 2696#endif
2cb720e9 2697
0db8a084 2698 WBHookSymbol(image, _UIKitBundle);
0db8a084 2699
d6f0973b
JF
2700 if (kCFCoreFoundationVersionNumber < 700)
2701 MSHookFunction(_UIImageWithName, MSHake(_UIImageWithName));
0db8a084
JF
2702
2703 WBHookSymbol(image, _UIApplicationImageWithName);
2704 MSHookFunction(_UIApplicationImageWithName, MSHake(_UIApplicationImageWithName));
2705
2706 WBHookSymbol(image, _UIImageWithNameInDomain);
2707 MSHookFunction(_UIImageWithNameInDomain, MSHake(_UIImageWithNameInDomain));
2708
712d0089
JF
2709 SEL includeEmoji(@selector(_legacy_drawAtPoint:forWidth:withFont:lineBreakMode:letterSpacing:includeEmoji:));
2710 if (![@"" respondsToSelector:includeEmoji])
2711 includeEmoji = @selector(drawAtPoint:forWidth:withFont:lineBreakMode:letterSpacing:includeEmoji:);
2712 MSHookMessage($NSString, includeEmoji, MSHake(NSString$drawAtPoint$forWidth$withFont$lineBreakMode$letterSpacing$includeEmoji$));
00182b65
JF
2713
2714 SEL letterSpacing(@selector(_legacy_sizeWithFont:forWidth:lineBreakMode:letterSpacing:));
2715 if (![@"" respondsToSelector:letterSpacing])
2716 letterSpacing = @selector(sizeWithFont:forWidth:lineBreakMode:letterSpacing:);
2717 MSHookMessage($NSString, letterSpacing, MSHake(NSString$sizeWithFont$forWidth$lineBreakMode$letterSpacing$));
2718
2719 SEL sizeWithFont(@selector(_legacy_sizeWithFont:));
2720 if (![@"" respondsToSelector:sizeWithFont])
2721 sizeWithFont = @selector(sizeWithFont:);
2722 MSHookMessage($NSString, sizeWithFont, MSHake(NSString$sizeWithFont$));
62ab6edb
JF
2723
2724 MSHookMessage($NSAttributedString, @selector(drawAtPoint:), MSHake(NSAttributedString$drawAtPoint$));
2725 MSHookMessage($NSAttributedString, @selector(boundingRectWithSize:options:context:), MSHake(NSAttributedString$boundingRectWithSize$options$context$));
e079e414
JF
2726 }
2727 // }}}
77d89d52 2728
a8a6d935
JF
2729 //MSHookFunction(reinterpret_cast<int (*)(const char *, int, mode_t)>(&open), MSHake(open));
2730
d5168fd6
JF
2731 [pool release];
2732}