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