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