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