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