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