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