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