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