]> git.saurik.com Git - winterboard.git/blob - Library.mm
95566f1924e32c297766e8985ebda71712a0f524
[winterboard.git] / Library.mm
1 /* WinterBoard - Theme Manager for the iPhone
2 * Copyright (C) 2008 Jay Freeman (saurik)
3 */
4
5 /*
6 * Redistribution and use in source and binary
7 * forms, with or without modification, are permitted
8 * provided that the following conditions are met:
9 *
10 * 1. Redistributions of source code must retain the
11 * above copyright notice, this list of conditions
12 * and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the
14 * above copyright notice, this list of conditions
15 * and the following disclaimer in the documentation
16 * and/or other materials provided with the
17 * distribution.
18 * 3. The name of the author may not be used to endorse
19 * or promote products derived from this software
20 * without specific prior written permission.
21 *
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS''
23 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
24 * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
25 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
27 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
28 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
32 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
33 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
34 * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
35 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
36 */
37
38 #define _trace() NSLog(@"WB:_trace(%u)", __LINE__);
39 #define _transient
40
41 #include <objc/runtime.h>
42 #include <objc/message.h>
43
44 #include <dlfcn.h>
45
46 extern "C" {
47 #include <mach-o/nlist.h>
48 }
49
50 #include <mach/mach_init.h>
51 #include <mach/vm_map.h>
52
53 #include <sys/mman.h>
54
55 #import <Foundation/Foundation.h>
56 #import <CoreGraphics/CoreGraphics.h>
57
58 #import <UIKit/UIColor.h>
59 #import <UIKit/UIFont.h>
60 #import <UIKit/UIImage.h>
61 #import <UIKit/UIImageView.h>
62 #import <UIKit/UINavigationBar.h>
63 #import <UIKit/UINavigationBarBackground.h>
64 #import <UIKit/UIToolbar.h>
65 #import <UIKit/UIWebDocumentView.h>
66
67 #import <UIKit/NSString-UIStringDrawing.h>
68 #import <UIKit/NSString-UIStringDrawingDeprecated.h>
69
70 #import <UIKit/UIImage-UIImageDeprecated.h>
71
72 #import <UIKit/UIView-Geometry.h>
73 #import <UIKit/UIView-Hierarchy.h>
74 #import <UIKit/UIView-Rendering.h>
75
76 #import <SpringBoard/SBApplication.h>
77 #import <SpringBoard/SBApplicationIcon.h>
78 #import <SpringBoard/SBAppWindow.h>
79 #import <SpringBoard/SBBookmarkIcon.h>
80 #import <SpringBoard/SBButtonBar.h>
81 #import <SpringBoard/SBContentLayer.h>
82 #import <SpringBoard/SBIconController.h>
83 #import <SpringBoard/SBIconLabel.h>
84 #import <SpringBoard/SBSlidingAlertDisplay.h>
85 #import <SpringBoard/SBStatusBarContentsView.h>
86 #import <SpringBoard/SBStatusBarController.h>
87 #import <SpringBoard/SBStatusBarTimeView.h>
88 #import <SpringBoard/SBUIController.h>
89
90 #import <MediaPlayer/MPVideoView.h>
91 #import <MediaPlayer/MPVideoView-PlaybackControl.h>
92
93 #import <CoreGraphics/CGGeometry.h>
94
95 extern "C" void __clear_cache (char *beg, char *end);
96
97 Class $MPVideoView;
98
99 Class $UIColor;
100 Class $UIImage;
101 Class $UIImageView;
102 Class $UIWebDocumentView;
103
104 @interface NSDictionary (WinterBoard)
105 - (UIColor *) colorForKey:(NSString *)key;
106 - (BOOL) boolForKey:(NSString *)key;
107 @end
108
109 @implementation NSDictionary (WinterBoard)
110
111 - (UIColor *) colorForKey:(NSString *)key {
112 NSString *value = [self objectForKey:key];
113 if (value == nil)
114 return nil;
115 /* XXX: incorrect */
116 return nil;
117 }
118
119 - (BOOL) boolForKey:(NSString *)key {
120 if (NSString *value = [self objectForKey:key])
121 return [value boolValue];
122 return false;
123 }
124
125 @end
126
127 bool Debug_ = false;
128 bool Engineer_ = true;
129
130 /* WinterBoard Backend {{{ */
131 #define WBPrefix "wb_"
132
133 void WBInject(const char *classname, const char *oldname, IMP newimp, const char *type) {
134 Class _class = objc_getClass(classname);
135 if (_class == nil)
136 return;
137 if (!class_addMethod(_class, sel_registerName(oldname), newimp, type))
138 NSLog(@"WB:Error: failed to inject [%s %s]", classname, oldname);
139 }
140
141 void WBRename(bool instance, const char *classname, const char *oldname, IMP newimp) {
142 Class _class = objc_getClass(classname);
143 if (_class == nil) {
144 if (Debug_)
145 NSLog(@"WB:Warning: cannot find class [%s]", classname);
146 return;
147 }
148 if (!instance)
149 _class = object_getClass(_class);
150 Method method = class_getInstanceMethod(_class, sel_getUid(oldname));
151 if (method == nil) {
152 if (Debug_)
153 NSLog(@"WB:Warning: cannot find method [%s %s]", classname, oldname);
154 return;
155 }
156 size_t namelen = strlen(oldname);
157 char newname[sizeof(WBPrefix) + namelen];
158 memcpy(newname, WBPrefix, sizeof(WBPrefix) - 1);
159 memcpy(newname + sizeof(WBPrefix) - 1, oldname, namelen + 1);
160 const char *type = method_getTypeEncoding(method);
161 if (!class_addMethod(_class, sel_registerName(newname), method_getImplementation(method), type))
162 NSLog(@"WB:Error: failed to rename [%s %s]", classname, oldname);
163 unsigned int count;
164 Method *methods = class_copyMethodList(_class, &count);
165 for (unsigned int index(0); index != count; ++index)
166 if (methods[index] == method)
167 goto found;
168 if (newimp != NULL)
169 if (!class_addMethod(_class, sel_getUid(oldname), newimp, type))
170 NSLog(@"WB:Error: failed to rename [%s %s]", classname, oldname);
171 goto done;
172 found:
173 if (newimp != NULL)
174 method_setImplementation(method, newimp);
175 done:
176 free(methods);
177 }
178 /* }}} */
179
180 @protocol WinterBoard
181 - (void) wb_updateDesktopImage:(UIImage *)image;
182 - (UIImage *) wb_defaultDesktopImage;
183 - (NSString *) wb_bundlePath;
184 - (NSString *) wb_pathForIcon;
185 - (NSString *) wb_pathForResource:(NSString *)resource ofType:(NSString *)type;
186 - (id) wb_init;
187 - (id) wb_layer;
188 - (id) wb_initWithSize:(CGSize)size;
189 - (id) wb_initWithSize:(CGSize)size label:(NSString *)label;
190 - (id) wb_initWithFrame:(CGRect)frame;
191 - (id) wb_initWithCoder:(NSCoder *)coder;
192 - (void) wb_setFrame:(CGRect)frame;
193 - (void) wb_drawRect:(CGRect)rect;
194 - (void) wb_setBackgroundColor:(id)color;
195 - (void) wb_setAlpha:(float)value;
196 - (void) wb_setBarStyle:(int)style;
197 - (id) wb_initWithFrame:(CGRect)frame withBarStyle:(int)style withTintColor:(UIColor *)color;
198 - (void) wb_setOpaque:(BOOL)opaque;
199 - (void) wb_setInDock:(BOOL)docked;
200 - (void) wb_didMoveToSuperview;
201 + (UIImage *) wb_imageNamed:(NSString *)name inBundle:(NSBundle *)bundle;
202 + (UIImage *) wb_applicationImageNamed:(NSString *)name;
203 - (NSDictionary *) wb_infoDictionary;
204 - (UIImage *) wb_icon;
205 - (void) wb_appendIconList:(SBIconList *)list;
206 - (id) wb_initWithStatusBar:(id)bar mode:(int)mode;
207 - (id) wb_initWithMode:(int)mode orientation:(int)orientation;
208 - (id) wb_imageAtPath:(NSString *)path;
209 - (id) wb_initWithContentsOfFile:(NSString *)file;
210 - (id) wb_initWithContentsOfFile:(NSString *)file cache:(BOOL)cache;
211 - (void) wb_setStatusBarMode:(int)mode orientation:(int)orientation duration:(float)duration fenceID:(int)id animation:(int)animation;
212 @end
213
214 static NSMutableDictionary **__mappedImages;
215 static NSMutableDictionary *UIImages_;
216 static NSMutableDictionary *PathImages_;
217
218 static NSFileManager *Manager_;
219 static NSDictionary *English_;
220 static NSMutableDictionary *Info_;
221 static NSMutableArray *themes_;
222
223 static NSString *$getTheme$(NSArray *files) {
224 for (NSString *theme in themes_)
225 for (NSString *file in files) {
226 NSString *path([NSString stringWithFormat:@"%@/%@", theme, file]);
227 if ([Manager_ fileExistsAtPath:path])
228 return path;
229 }
230
231 return nil;
232 }
233
234 static NSString *$pathForIcon$(SBApplication<WinterBoard> *self) {
235 for (NSString *theme in themes_) {
236 NSString *identifier = [self bundleIdentifier];
237 NSString *folder = [[self path] lastPathComponent];
238 NSString *dname = [self displayName];
239 NSString *didentifier = [self displayIdentifier];
240
241 if (Debug_)
242 NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier);
243
244 #define testForIcon(Name) \
245 if (NSString *name = Name) { \
246 NSString *path = [NSString stringWithFormat:@"%@/Icons/%@.png", theme, name]; \
247 if ([Manager_ fileExistsAtPath:path]) \
248 return path; \
249 }
250
251 if (identifier != nil) {
252 NSString *path = [NSString stringWithFormat:@"%@/Bundles/%@/icon.png", theme, identifier];
253 if ([Manager_ fileExistsAtPath:path])
254 return path;
255 }
256
257 if (folder != nil) {
258 NSString *path = [NSString stringWithFormat:@"%@/Folders/%@/icon.png", theme, folder];
259 if ([Manager_ fileExistsAtPath:path])
260 return path;
261 }
262
263 testForIcon(identifier);
264 testForIcon(dname);
265
266 if (didentifier != nil) {
267 testForIcon([English_ objectForKey:didentifier]);
268
269 NSArray *parts = [didentifier componentsSeparatedByString:@"-"];
270 if ([parts count] != 1)
271 if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[[self path] stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease])
272 testForIcon([english objectForKey:[parts lastObject]]);
273 }
274 }
275
276 return nil;
277 }
278
279 static UIImage *SBApplicationIcon$icon(SBApplicationIcon<WinterBoard> *self, SEL sel) {
280 if (![Info_ boolForKey:@"ComposeStoreIcons"])
281 if (NSString *path = $pathForIcon$([self application]))
282 return [$UIImage imageWithContentsOfFile:path];
283 return [self wb_icon];
284 }
285
286 static UIImage *SBBookmarkIcon$icon(SBBookmarkIcon<WinterBoard> *self, SEL sel) {
287 if (Debug_)
288 NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]);
289 if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]]))
290 return [$UIImage imageWithContentsOfFile:path];
291 return [self wb_icon];
292 }
293
294 static NSString *SBApplication$pathForIcon(SBApplication<WinterBoard> *self, SEL sel) {
295 if (NSString *path = $pathForIcon$(self))
296 return path;
297 return [self wb_pathForIcon];
298 }
299
300 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle<WinterBoard> *bundle, bool ui) {
301 for (NSString *theme in themes_) {
302 NSString *identifier = [bundle bundleIdentifier];
303
304 if (identifier != nil) {
305 NSString *path = [NSString stringWithFormat:@"%@/Bundles/%@/%@", theme, identifier, file];
306 if ([Manager_ fileExistsAtPath:path])
307 return path;
308 }
309
310 if (NSString *folder = [[bundle wb_bundlePath] lastPathComponent]) {
311 NSString *path = [NSString stringWithFormat:@"%@/Folders/%@/%@", theme, folder, file];
312 if ([Manager_ fileExistsAtPath:path])
313 return path;
314 }
315
316 #define remapResourceName(oldname, newname) \
317 else if ([file isEqualToString:oldname]) { \
318 NSString *path = [NSString stringWithFormat:@"%@/%@.png", theme, newname]; \
319 if ([Manager_ fileExistsAtPath:path]) \
320 return path; \
321 }
322
323 if (identifier == nil || ![identifier isEqualToString:@"com.apple.springboard"]);
324 remapResourceName(@"FSO_BG.png", @"StatusBar")
325 remapResourceName(@"SBDockBG.png", @"Dock")
326 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
327
328 if (ui) {
329 NSString *path = [NSString stringWithFormat:@"%@/UIImages/%@", theme, file];
330 if ([Manager_ fileExistsAtPath:path])
331 return path;
332 }
333 }
334
335 return nil;
336 }
337
338 static UIImage *CachedImageAtPath(NSString *path) {
339 UIImage *image = [PathImages_ objectForKey:path];
340 if (image != nil)
341 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
342 image = [[$UIImage alloc] wb_initWithContentsOfFile:path cache:true];
343 if (image != nil)
344 image = [image autorelease];
345 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path];
346 return image;
347 }
348
349 static UIImage *UIImage$imageNamed$inBundle$(Class<WinterBoard> self, SEL sel, NSString *name, NSBundle *bundle) {
350 NSString *key = [NSString stringWithFormat:@"%@/%@", [bundle bundleIdentifier], name];
351 UIImage *image = [PathImages_ objectForKey:key];
352 if (image != nil)
353 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
354 if (Debug_)
355 NSLog(@"WB:Debug: [UIImage(%@) imageNamed:\"%@\"]", [bundle bundleIdentifier], name);
356 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
357 image = CachedImageAtPath(path);
358 if (image == nil)
359 image = [self wb_imageNamed:name inBundle:bundle];
360 [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
361 return image;
362 }
363
364 static UIImage *UIImage$imageNamed$(Class<WinterBoard> self, SEL sel, NSString *name) {
365 return UIImage$imageNamed$inBundle$(self, sel, name, [NSBundle mainBundle]);
366 }
367
368 static UIImage *UIImage$applicationImageNamed$(Class<WinterBoard> self, SEL sel, NSString *name) {
369 NSBundle *bundle = [NSBundle mainBundle];
370 if (Debug_)
371 NSLog(@"WB:Debug: [UIImage(%@) applicationImageNamed:\"%@\"]", [bundle bundleIdentifier], name);
372 if (NSString *path = $pathForFile$inBundle$(name, bundle, false))
373 return CachedImageAtPath(path);
374 return [self wb_applicationImageNamed:name];
375 }
376
377 @interface NSString (WinterBoard)
378 - (NSString *) wb_themedPath;
379 @end
380
381 @implementation NSString (WinterBoard)
382
383 - (NSString *) wb_themedPath {
384 NSLog(@"WB:Debug:Bypass(\"%@\")", self);
385 return self;
386 }
387
388 @end
389
390 static NSMutableDictionary *Files_;
391
392 #define WBDelegate(delegate) \
393 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
394 if (Engineer_) \
395 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
396 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
397 return sig; \
398 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
399 return nil; \
400 } \
401 \
402 - (void) forwardInvocation:(NSInvocation*)inv { \
403 SEL sel = [inv selector]; \
404 if ([delegate respondsToSelector:sel]) \
405 [inv invokeWithTarget:delegate]; \
406 else \
407 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
408 }
409
410 /*@interface WBBundlePath : NSProxy {
411 NSBundle<WinterBoard> *bundle_;
412 NSString *path_;
413 }
414
415 - (id) initWithBundle:(NSBundle *)bundle path:(NSString *)path;
416
417 - (NSString *) wb_themedPath;
418
419 @end
420
421 @implementation WBBundlePath
422
423 - (void) dealloc {
424 [bundle_ release];
425 [path_ release];
426 [super dealloc];
427 }
428
429 - (id) initWithBundle:(NSBundle *)bundle path:(NSString *)path {
430 bundle_ = [bundle retain];
431 path_ = [path retain];
432 return self;
433 }
434
435 WBDelegate(path_)
436
437 - (NSString *) stringByAppendingPathComponent:(NSString *)component {
438 NSLog(@"WB:Debug:app:%@:%@", path_, component);
439 return [[[WBBundlePath alloc] initWithBundle:bundle_ path:[path_ stringByAppendingPathComponent:component]] autorelease];
440 }
441
442 - (NSString *) stringByAppendingPathExtension:(NSString *)extension {
443 return [[[WBBundlePath alloc] initWithBundle:bundle_ path:[path_ stringByAppendingPathExtension:extension]] autorelease];
444 }
445
446 - (const char *) UTF8String {
447 const char *string = [path_ UTF8String];
448 NSLog(@"WB:Debug:UTF=%s", string);
449 return string;
450 }
451
452 - (NSString *) description {
453 return [path_ description];
454 }
455
456 - (NSString *) wb_themedPath {
457 return path_;
458 NSString *path = [Files_ objectForKey:path_];
459 if (path == nil) {
460 NSString *path = [bundle_ wb_bundlePath];
461 if (![path_ hasPrefix:path]) {
462 NSLog(@"WB:Error:![@\"%@\" hasPrefix:@\"%@\"]", path_, path);
463 return path_;
464 }
465 path = [path_ substringFromIndex:([path length] + 1)];
466 path = $pathForFile$inBundle$(path, bundle_, false);
467 if (path == nil)
468 path = reinterpret_cast<NSString *>([NSNull null]);
469 [Files_ setObject:path forKey:path_];
470 if (Debug_)
471 NSLog(@"WB:Debug:ThemePath(\"%@\")->\"%@\"", path_, path);
472 }
473 if (reinterpret_cast<id>(path) == [NSNull null])
474 path = path_;
475 NSLog(@"WB:Debug:ThemePath=%@", path);
476 return path;
477 }
478
479 @end*/
480
481 static NSString *NSBundle$bundlePath$(NSBundle<WinterBoard> *self, SEL sel) {
482 //return [[WBBundlePath alloc] initWithBundle:self path:[self wb_bundlePath]];
483 return [self wb_bundlePath];
484 }
485
486 static NSString *NSBundle$pathForResource$ofType$(NSBundle<WinterBoard> *self, SEL sel, NSString *resource, NSString *type) {
487 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
488 if (Debug_)
489 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
490 if (NSString *path = $pathForFile$inBundle$(file, self, false))
491 return path;
492 return [self wb_pathForResource:resource ofType:type];
493 }
494
495 static bool $setBarStyle$_(NSString *name, UIView<WinterBoard> *self, int style) {
496 if (Debug_)
497 NSLog(@"WB:Debug:%@Style:%d", name, style);
498 NSNumber *number = nil;
499 if (number == nil)
500 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]];
501 if (number == nil)
502 number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]];
503 if (number == nil)
504 return false;
505 else {
506 style = [number intValue];
507 if (Debug_)
508 NSLog(@"WB:Debug:%@Style=%d", name, style);
509 [self wb_setBarStyle:style];
510 return true;
511 }
512 }
513
514 /*static id UINavigationBarBackground$initWithFrame$withBarStyle$withTintColor$(UINavigationBarBackground<WinterBoard> *self, SEL sel, CGRect frame, int style, UIColor *tint) {
515 _trace();
516
517 if (NSNumber *number = [Info_ objectForKey:@"NavigationBarStyle"])
518 style = [number intValue];
519
520 if (UIColor *color = [Info_ colorForKey:@"NavigationBarTint"])
521 tint = color;
522
523 return [self wb_initWithFrame:frame withBarStyle:style withTintColor:tint];
524 }*/
525
526 /*static id UINavigationBar$initWithCoder$(SBAppWindow<WinterBoard> *self, SEL sel, CGRect frame, NSCoder *coder) {
527 self = [self wb_initWithCoder:coder];
528 if (self == nil)
529 return nil;
530 UINavigationBar$setBarStyle$_(self);
531 return self;
532 }
533
534 static id UINavigationBar$initWithFrame$(SBAppWindow<WinterBoard> *self, SEL sel, CGRect frame) {
535 self = [self wb_initWithFrame:frame];
536 if (self == nil)
537 return nil;
538 UINavigationBar$setBarStyle$_(self);
539 return self;
540 }*/
541
542 static void UIToolbar$setBarStyle$(UIToolbar<WinterBoard> *self, SEL sel, int style) {
543 if ($setBarStyle$_(@"Toolbar", self, style))
544 return;
545 return [self wb_setBarStyle:style];
546 }
547
548 static void UINavigationBar$setBarStyle$(UINavigationBar<WinterBoard> *self, SEL sel, int style) {
549 if ($setBarStyle$_(@"NavigationBar", self, style))
550 return;
551 return [self wb_setBarStyle:style];
552 }
553
554 static void $didMoveToSuperview(SBButtonBar<WinterBoard> *self, SEL sel) {
555 [[self superview] setBackgroundColor:[$UIColor clearColor]];
556 [self wb_didMoveToSuperview];
557 }
558
559 static id UIImage$imageAtPath$(NSObject<WinterBoard> *self, SEL sel, NSString *path) {
560 return [self wb_imageAtPath:[path wb_themedPath]];
561 }
562
563 static id $initWithContentsOfFile$(NSObject<WinterBoard> *self, SEL sel, NSString *file) {
564 return [self wb_initWithContentsOfFile:[file wb_themedPath]];
565 }
566
567 static id UIImage$initWithContentsOfFile$cache$(UIImage<WinterBoard> *self, SEL sel, NSString *file, BOOL cache) {
568 return [self wb_initWithContentsOfFile:[file wb_themedPath] cache:cache];
569 }
570
571 static UIImage *UIImage$defaultDesktopImage$(UIImage<WinterBoard> *self, SEL sel) {
572 if (Debug_)
573 NSLog(@"WB:Debug:DefaultDesktopImage");
574 if (NSString *path = $getTheme$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil]))
575 return [$UIImage imageWithContentsOfFile:path];
576 return [self wb_defaultDesktopImage];
577 }
578
579 static UIImageView *WallpaperImage_;
580 static UIWebDocumentView *WallpaperPage_;
581 static NSURL *WallpaperURL_;
582
583 static id SBContentLayer$initWithSize$(SBContentLayer<WinterBoard> *self, SEL sel, CGSize size) {
584 self = [self wb_initWithSize:size];
585 if (self == nil)
586 return nil;
587
588 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"])) {
589 MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[self bounds]] autorelease];
590 [video setMovieWithPath:path];
591 [video setRepeatMode:1];
592 [video setRepeatGap:0];
593 [self addSubview:video];
594 [video playFromBeginning];;
595 }
596
597 UIImage *image;
598 if (NSString *path = $getTheme$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil])) {
599 image = [[$UIImage alloc] wb_initWithContentsOfFile:path];
600 if (image != nil)
601 image = [image autorelease];
602 } else image = nil;
603
604 if (WallpaperImage_ != nil)
605 [WallpaperImage_ release];
606 WallpaperImage_ = [[$UIImageView alloc] initWithImage:image];
607 [self addSubview:WallpaperImage_];
608
609 if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"])) {
610 CGRect bounds = [self bounds];
611
612 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
613 [view setAutoresizes:true];
614
615 if (WallpaperPage_ != nil)
616 [WallpaperPage_ release];
617 WallpaperPage_ = [view retain];
618
619 if (WallpaperURL_ != nil)
620 [WallpaperURL_ release];
621 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
622
623 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
624
625 [[view webView] setDrawsBackground:false];
626 [view setBackgroundColor:[$UIColor clearColor]];
627
628 [self addSubview:view];
629 }
630
631 return self;
632 }
633
634 static void SBSlidingAlertDisplay$updateDesktopImage$(SBSlidingAlertDisplay<WinterBoard> *self, SEL sel, UIImage *image) {
635 NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]);
636
637 if (path) {
638 UIView *background;
639 object_getInstanceVariable(self, "_backgroundView", reinterpret_cast<void **>(&background));
640 if (background != nil)
641 path = nil;
642 }
643
644 [self wb_updateDesktopImage:image];
645
646 if (path != nil) {
647 CGRect bounds = [self bounds];
648
649 UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
650 [view setAutoresizes:true];
651
652 if (WallpaperPage_ != nil)
653 [WallpaperPage_ release];
654 WallpaperPage_ = [view retain];
655
656 if (WallpaperURL_ != nil)
657 [WallpaperURL_ release];
658 WallpaperURL_ = [[NSURL fileURLWithPath:path] retain];
659
660 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
661
662 [[view webView] setDrawsBackground:false];
663 [view setBackgroundColor:[$UIColor clearColor]];
664
665 UIView *background;
666 object_getInstanceVariable(self, "_backgroundView", reinterpret_cast<void **>(&background));
667 NSLog(@"back:%@", background);
668
669 [self insertSubview:view aboveSubview:background];
670 }
671 }
672
673 static unsigned *__currentContextCount;
674 static void ***__currentContextStack;
675
676 /*extern "C" CGColorRef CGGStateGetSystemColor(void *);
677 extern "C" CGColorRef CGGStateGetFillColor(void *);
678 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
679 extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/
680
681 @interface WBTime : NSProxy {
682 NSString *time_;
683 _transient SBStatusBarTimeView *view_;
684 }
685
686 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
687
688 @end
689
690 @implementation WBTime
691
692 - (void) dealloc {
693 [time_ release];
694 [super dealloc];
695 }
696
697 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
698 time_ = [time retain];
699 view_ = view;
700 return self;
701 }
702
703 WBDelegate(time_)
704
705 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
706 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
707 BOOL mode;
708 object_getInstanceVariable(view_, "_mode", reinterpret_cast<void **>(&mode));
709
710 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
711 "font-family: Helvetica; "
712 "font-weight: bold; "
713 "font-size: 14px; "
714 "color: %@; "
715 "%@", mode ? @"white" : @"black", custom]];
716
717 return CGSizeZero;
718 }
719
720 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
721 }
722
723 @end
724
725 @interface WBIconLabel : NSProxy {
726 NSString *string_;
727 BOOL docked_;
728 }
729
730 - (id) initWithString:(NSString *)string;
731
732 @end
733
734 @implementation WBIconLabel
735
736 - (void) dealloc {
737 [string_ release];
738 [super dealloc];
739 }
740
741 - (id) initWithString:(NSString *)string {
742 string_ = [string retain];
743 return self;
744 }
745
746 WBDelegate(string_)
747
748 - (NSString *) _iconLabelStyle {
749 NSString *key = docked_ ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle";
750 NSString *style = [Info_ objectForKey:key];
751 return style;
752 }
753
754 - (CGSize) drawInRect:(CGRect)rect withFont:(UIFont *)font lineBreakMode:(int)mode alignment:(int)alignment {
755 if (NSString *custom = [self _iconLabelStyle]) {
756 NSString *style = [NSString stringWithFormat:@""
757 "font-family: Helvetica; "
758 "font-weight: bold; "
759 "font-size: 11px; "
760 "text-align: center; "
761 "color: %@; "
762 "%@", docked_ ? @"white" : @"#b3b3b3", custom];
763
764 if (Debug_)
765 NSLog(@"WB:Debug:style = %@", style);
766 [string_ drawInRect:rect withStyle:style];
767 return CGSizeZero;
768 }
769
770 return [string_ drawInRect:rect withFont:font lineBreakMode:mode alignment:alignment];
771 }
772
773 - (void) drawInRect:(CGRect)rect withStyle:(NSString *)style {
774 if (NSString *custom = [self _iconLabelStyle]) {
775 NSString *combined = [NSString stringWithFormat:@"%@; %@", style, custom];
776 if (Debug_)
777 NSLog(@"WB:Debug:combined = %@", combined);
778 return [string_ drawInRect:rect withStyle:combined];
779 }
780 return [string_ drawInRect:rect withStyle:style];
781 }
782
783 - (BOOL) respondsToSelector:(SEL)sel {
784 return
785 sel == @selector(setInDock:)
786 ? true : [super respondsToSelector:sel];
787 }
788
789 - (void) setInDock:(BOOL)docked {
790 docked_ = docked;
791 }
792
793 @end
794
795 static void SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(SBStatusBarController<WinterBoard> *self, SEL sel, int mode, int orientation, float duration, int id, int animation) {
796 if (Debug_)
797 NSLog(@"WB:Debug:setStatusBarMode:%d", mode);
798 if (mode < 100) // 104:hidden 105:glowing
799 if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"])
800 mode = [number intValue];
801 return [self wb_setStatusBarMode:mode orientation:orientation duration:duration fenceID:id animation:animation];
802 }
803
804 /*static id SBStatusBar$initWithMode$orientation$(SBStatusBar<WinterBoard> *self, SEL sel, int mode, int orientation) {
805 return [self wb_initWithMode:mode orientation:orientation];
806 }*/
807
808 static id SBStatusBarContentsView$initWithStatusBar$mode$(SBStatusBarContentsView<WinterBoard> *self, SEL sel, id bar, int mode) {
809 if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"])
810 mode = [number intValue];
811 return [self wb_initWithStatusBar:bar mode:mode];
812 }
813
814 static void SBStatusBarTimeView$drawRect$(SBStatusBarTimeView<WinterBoard> *self, SEL sel, CGRect rect) {
815 id time;
816 object_getInstanceVariable(self, "_time", reinterpret_cast<void **>(&time));
817 if (time != nil && [time class] != [WBTime class])
818 object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTime alloc] initWithTime:[time autorelease] view:self]));
819 return [self wb_drawRect:rect];
820 }
821
822 static void SBIconController$appendIconList$(SBIconController<WinterBoard> *self, SEL sel, SBIconList *list) {
823 if (Debug_)
824 NSLog(@"appendIconList:%@", list);
825 return [self wb_appendIconList:list];
826 }
827
828 static void SBIconLabel$setInDock$(SBIconLabel<WinterBoard> *self, SEL sel, BOOL docked) {
829 id label;
830 object_getInstanceVariable(self, "_label", reinterpret_cast<void **>(&label));
831 if (![Info_ boolForKey:@"UndockedIconLabels"])
832 docked = true;
833 if (label != nil && [label respondsToSelector:@selector(setInDock:)])
834 [label setInDock:docked];
835 return [self wb_setInDock:docked];
836 }
837
838 static id SBIconLabel$initWithSize$label$(SBIconLabel<WinterBoard> *self, SEL sel, CGSize size, NSString *label) {
839 // XXX: technically I'm misusing self here
840 return [self wb_initWithSize:size label:[[[WBIconLabel alloc] initWithString:label] autorelease]];
841 //return [self wb_initWithSize:size label:label];
842 }
843
844 extern "C" void FindMappedImages(void);
845 extern "C" NSData *UIImagePNGRepresentation(UIImage *);
846
847 static UIImage *(*_UIImageAtPath)(NSString *name, NSBundle *path);
848 static CGImageRef *(*_UIImageRefAtPath)(NSString *path, bool cache, UIImageOrientation *orientation);
849 static UIImage *(*_UIImageWithName)(NSString *name);
850 static NSBundle *(*_UIKitBundle)();
851 static void (*_UISharedImageInitialize)(bool);
852 static int (*_UISharedImageNameGetIdentifier)(NSString *);
853 static UIImage *(*_UISharedImageWithIdentifier)(int);
854
855 static UIImage *$_UIImageWithName(NSString *name) {
856 int id(_UISharedImageNameGetIdentifier(name));
857 if (Debug_)
858 NSLog(@"WB:Debug: UIImageWithName(\"%@\", %d)", name, id);
859
860 if (id == -1)
861 return _UIImageAtPath(name, _UIKitBundle());
862 else {
863 NSNumber *key([NSNumber numberWithInt:id]);
864 UIImage *image = [UIImages_ objectForKey:key];
865 if (image != nil)
866 return reinterpret_cast<id>(image) == [NSNull null] ? nil : image;
867 if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true)) {
868 image = [[$UIImage alloc] wb_initWithContentsOfFile:path];
869 if (image != nil)
870 [image autorelease];
871 }
872 if (image == nil)
873 image = _UISharedImageWithIdentifier(id);
874 [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key];
875 return image;
876 }
877 }
878
879 // ldr pc, [pc, #-4]
880 #define ldr_pc_$pc_m4$ 0xe51ff004
881
882 template <typename Type_>
883 static void WBReplace(Type_ *symbol, Type_ *replace, Type_ **result) {
884 if (Debug_)
885 NSLog(@"WB:Notice: Remapping %p to %p", symbol, replace);
886 if (symbol == NULL)
887 return;
888
889 int page = getpagesize();
890 uintptr_t base = reinterpret_cast<uintptr_t>(symbol) / page * page;
891
892 mach_port_t self = mach_task_self();
893
894 if (kern_return_t error = vm_protect(self, base, page, FALSE, VM_PROT_READ | VM_PROT_WRITE | VM_PROT_COPY)) {
895 NSLog(@"WB:Error:vm_protect():%d", error);
896 return;
897 }
898
899 uint32_t *code = reinterpret_cast<uint32_t *>(symbol);
900 uint32_t backup[2] = {code[0], code[1]};
901
902 code[0] = ldr_pc_$pc_m4$;
903 code[1] = reinterpret_cast<uint32_t>(replace);
904
905 __clear_cache(reinterpret_cast<char *>(code), reinterpret_cast<char *>(code + 2));
906
907 if (kern_return_t error = vm_protect(self, base, page, FALSE, VM_PROT_READ | VM_PROT_EXECUTE))
908 NSLog(@"WB:Error:vm_protect():%d", error);
909
910 if (result != NULL) {
911 uint32_t *buffer = reinterpret_cast<uint32_t *>(mmap(
912 NULL, sizeof(uint32_t) * 4,
913 PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE,
914 -1, 0
915 ));
916
917 if (buffer == MAP_FAILED) {
918 NSLog(@"WB:Error:mmap():%d", errno);
919 return;
920 }
921
922 buffer[0] = backup[0];
923 buffer[1] = backup[1];
924 buffer[2] = ldr_pc_$pc_m4$;
925 buffer[3] = reinterpret_cast<uint32_t>(code + 2);
926
927 if (mprotect(buffer, sizeof(uint32_t) * 4, PROT_READ | PROT_EXEC) == -1) {
928 NSLog(@"WB:Error:mprotect():%d", errno);
929 return;
930 }
931
932 *result = reinterpret_cast<Type_ *>(buffer);
933 }
934 }
935
936 template <typename Type_>
937 static void WBReplace(Type_ *symbol, Type_ *replace) {
938 return WBReplace(symbol, replace, static_cast<Type_ **>(NULL));
939 }
940
941 #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox"
942 #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit"
943
944 /*static void UIWebDocumentView$setViewportSize$forDocumentTypes$(UIWebDocumentView *self, SEL sel, CGSize size, int type) {
945 NSLog(@"WB:Examine: %f:%f:%u", size.width, size.height, type);
946 }*/
947
948 static bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long, char *, bool &);
949
950 static bool $_Z24GetFileNameForThisActionmPcRb(unsigned long a0, char *a1, bool &a2) {
951 bool value = _Z24GetFileNameForThisActionmPcRb(a0, a1, a2);
952 if (Debug_)
953 NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value);
954
955 if (value) {
956 NSString *path = [NSString stringWithUTF8String:a1];
957 if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) {
958 NSString *file = [path substringFromIndex:31];
959 NSLog(@"%@", file);
960 for (NSString *theme in themes_) {
961 NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]);
962 if ([Manager_ fileExistsAtPath:path]) {
963 strcpy(a1, [path UTF8String]);
964 continue;
965 }
966 }
967 }
968 }
969 return value;
970 }
971
972 static void ChangeWallpaper(
973 CFNotificationCenterRef center,
974 void *observer,
975 CFStringRef name,
976 const void *object,
977 CFDictionaryRef info
978 ) {
979 if (Debug_)
980 NSLog(@"WB:Debug:ChangeWallpaper!");
981
982 UIImage *image;
983 if (NSString *path = $getTheme$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil])) {
984 image = [[$UIImage alloc] wb_initWithContentsOfFile:path];
985 if (image != nil)
986 image = [image autorelease];
987 } else image = nil;
988
989 if (WallpaperImage_ != nil)
990 [WallpaperImage_ setImage:image];
991 if (WallpaperPage_ != nil)
992 [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]];
993
994 }
995
996 extern "C" void WBInitialize() {
997 if (dlopen(UIKit, RTLD_LAZY | RTLD_NOLOAD) == NULL)
998 return;
999 NSLog(@"WB:Notice: Installing WinterBoard...");
1000
1001 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
1002
1003 NSBundle *MediaPlayer = [NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"];
1004 if (MediaPlayer != nil)
1005 [MediaPlayer load];
1006
1007 $MPVideoView = objc_getClass("MPVideoView");
1008
1009 $UIColor = objc_getClass("UIColor");
1010 $UIImage = objc_getClass("UIImage");
1011 $UIImageView = objc_getClass("UIImageView");
1012 $UIWebDocumentView = objc_getClass("UIWebDocumentView");
1013
1014 struct nlist nl[11];
1015 memset(nl, 0, sizeof(nl));
1016
1017 nl[0].n_un.n_name = (char *) "___currentContextCount";
1018 nl[1].n_un.n_name = (char *) "___currentContextStack";
1019 nl[2].n_un.n_name = (char *) "___mappedImages";
1020 nl[3].n_un.n_name = (char *) "__UIImageAtPath";
1021 nl[4].n_un.n_name = (char *) "__UIImageRefAtPath";
1022 nl[5].n_un.n_name = (char *) "__UIImageWithName";
1023 nl[6].n_un.n_name = (char *) "__UIKitBundle";
1024 nl[7].n_un.n_name = (char *) "__UISharedImageInitialize";
1025 nl[8].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier";
1026 nl[9].n_un.n_name = (char *) "__UISharedImageWithIdentifier";
1027
1028 nlist(UIKit, nl);
1029
1030 __currentContextCount = (unsigned *) nl[0].n_value;
1031 __currentContextStack = (void ***) nl[1].n_value;
1032 __mappedImages = (id *) nl[2].n_value;
1033 _UIImageAtPath = (UIImage *(*)(NSString *, NSBundle *)) nl[3].n_value;
1034 _UIImageRefAtPath = (CGImageRef *(*)(NSString *, bool, UIImageOrientation *)) nl[4].n_value;
1035 _UIImageWithName = (UIImage *(*)(NSString *)) nl[5].n_value;
1036 _UIKitBundle = (NSBundle *(*)()) nl[6].n_value;
1037 _UISharedImageInitialize = (void (*)(bool)) nl[7].n_value;
1038 _UISharedImageNameGetIdentifier = (int (*)(NSString *)) nl[8].n_value;
1039 _UISharedImageWithIdentifier = (UIImage *(*)(int)) nl[9].n_value;
1040
1041 WBReplace(_UIImageWithName, &$_UIImageWithName);
1042
1043 if (dlopen(AudioToolbox, RTLD_LAZY | RTLD_NOLOAD) != NULL) {
1044 struct nlist nl[2];
1045 memset(nl, 0, sizeof(nl));
1046 nl[0].n_un.n_name = (char *) "__Z24GetFileNameForThisActionmPcRb";
1047 nlist(AudioToolbox, nl);
1048 _Z24GetFileNameForThisActionmPcRb = (bool (*)(unsigned long, char *, bool &)) nl[0].n_value;
1049 WBReplace(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &_Z24GetFileNameForThisActionmPcRb);
1050 }
1051
1052 WBRename(false, "UIImage", "applicationImageNamed:", (IMP) &UIImage$applicationImageNamed$);
1053 WBRename(false, "UIImage", "defaultDesktopImage", (IMP) &UIImage$defaultDesktopImage$);
1054 WBRename(false, "UIImage", "imageAtPath:", (IMP) &UIImage$imageAtPath$);
1055 WBRename(false, "UIImage", "imageNamed:", (IMP) &UIImage$imageNamed$);
1056 WBRename(false, "UIImage", "imageNamed:inBundle:", (IMP) &UIImage$imageNamed$inBundle$);
1057
1058 //WBRename("UINavigationBar", "initWithCoder:", (IMP) &UINavigationBar$initWithCoder$);
1059 //WBRename("UINavigationBarBackground", "initWithFrame:withBarStyle:withTintColor:", (IMP) &UINavigationBarBackground$initWithFrame$withBarStyle$withTintColor$);
1060 //WBRename(true, "SBStatusBar", "initWithMode:orientation:", (IMP) &SBStatusBar$initWithMode$orientation$);
1061 //WBRename(true, "UIWebDocumentView", "setViewportSize:forDocumentTypes:", (IMP) &UIWebDocumentView$setViewportSize$forDocumentTypes$);
1062
1063 WBRename(true, "NSBundle", "bundlePath", (IMP) &NSBundle$bundlePath$);
1064 WBRename(true, "NSBundle", "pathForResource:ofType:", (IMP) &NSBundle$pathForResource$ofType$);
1065
1066 WBRename(true, "UIImage", "initWithContentsOfFile:", (IMP) &$initWithContentsOfFile$);
1067 WBRename(true, "UIImage", "initWithContentsOfFile:cache:", (IMP) &UIImage$initWithContentsOfFile$cache$);
1068 WBRename(true, "UINavigationBar", "setBarStyle:", (IMP) &UINavigationBar$setBarStyle$);
1069 WBRename(true, "UIToolbar", "setBarStyle:", (IMP) &UIToolbar$setBarStyle$);
1070
1071 WBRename(true, "SBApplication", "pathForIcon", (IMP) &SBApplication$pathForIcon);
1072 WBRename(true, "SBApplicationIcon", "icon", (IMP) &SBApplicationIcon$icon);
1073 WBRename(true, "SBBookmarkIcon", "icon", (IMP) &SBBookmarkIcon$icon);
1074 WBRename(true, "SBButtonBar", "didMoveToSuperview", (IMP) &$didMoveToSuperview);
1075 WBRename(true, "SBContentLayer", "initWithSize:", (IMP) &SBContentLayer$initWithSize$);
1076 WBRename(true, "SBIconLabel", "setInDock:", (IMP) &SBIconLabel$setInDock$);
1077 WBRename(true, "SBIconLabel", "initWithSize:label:", (IMP) &SBIconLabel$initWithSize$label$);
1078 WBRename(true, "SBSlidingAlertDisplay", "updateDesktopImage:", (IMP) &SBSlidingAlertDisplay$updateDesktopImage$);
1079 WBRename(true, "SBStatusBarContentsView", "didMoveToSuperview", (IMP) &$didMoveToSuperview);
1080 WBRename(true, "SBStatusBarContentsView", "initWithStatusBar:mode:", (IMP) &SBStatusBarContentsView$initWithStatusBar$mode$);
1081 WBRename(true, "SBStatusBarController", "setStatusBarMode:orientation:duration:fenceID:animation:", (IMP) &SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$);
1082 WBRename(true, "SBStatusBarTimeView", "drawRect:", (IMP) &SBStatusBarTimeView$drawRect$);
1083 WBRename(true, "SBIconController", "appendIconList:", (IMP) &SBIconController$appendIconList$);
1084
1085 _UISharedImageInitialize(false);
1086
1087 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
1088 if (English_ != nil)
1089 English_ = [English_ retain];
1090
1091 Manager_ = [[NSFileManager defaultManager] retain];
1092 UIImages_ = [[NSMutableDictionary alloc] initWithCapacity:16];
1093 PathImages_ = [[NSMutableDictionary alloc] initWithCapacity:16];
1094 Files_ = [[NSMutableDictionary alloc] initWithCapacity:16];
1095
1096 themes_ = [[NSMutableArray alloc] initWithCapacity:8];
1097
1098 if (NSDictionary *settings = [[NSDictionary alloc] initWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) {
1099 [settings autorelease];
1100
1101 if (NSNumber *debug = [settings objectForKey:@"Debug"])
1102 Debug_ = [debug boolValue];
1103
1104 NSArray *themes = [settings objectForKey:@"Themes"];
1105 if (themes == nil)
1106 if (NSString *theme = [settings objectForKey:@"Theme"])
1107 themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys:
1108 theme, @"Name",
1109 [NSNumber numberWithBool:true], @"Active",
1110 nil]];
1111 if (themes != nil)
1112 for (NSDictionary *theme in themes) {
1113 NSNumber *active = [theme objectForKey:@"Active"];
1114 if (![active boolValue])
1115 continue;
1116
1117 NSString *name = [theme objectForKey:@"Name"];
1118 if (name == nil)
1119 continue;
1120
1121 NSString *theme = nil;
1122
1123 #define testForTheme(format...) \
1124 if (theme == nil) { \
1125 NSString *path = [NSString stringWithFormat:format]; \
1126 if ([Manager_ fileExistsAtPath:path]) { \
1127 [themes_ addObject:path]; \
1128 continue; \
1129 } \
1130 }
1131
1132 testForTheme(@"/Library/Themes/%@.theme", name)
1133 testForTheme(@"/Library/Themes/%@", name)
1134 testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name)
1135 }
1136 }
1137
1138 Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain];
1139
1140 for (NSString *theme in themes_)
1141 if (NSDictionary *info = [[NSDictionary alloc] initWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]])
1142 for (NSString *key in [info allKeys])
1143 if ([Info_ objectForKey:key] == nil)
1144 [Info_ setObject:[info objectForKey:key] forKey:key];
1145
1146 if (objc_getClass("SpringBoard") != nil)
1147 CFNotificationCenterAddObserver(
1148 CFNotificationCenterGetDarwinNotifyCenter(),
1149 NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0
1150 );
1151
1152 if ([Info_ objectForKey:@"UndockedIconLabels"] == nil)
1153 [Info_ setObject:[NSNumber numberWithBool:(
1154 [Info_ objectForKey:@"DockedIconLabelStyle"] != nil ||
1155 [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil
1156 )] forKey:@"UndockedIconLabels"];
1157
1158 if (![Info_ boolForKey:@"UndockedIconLabels"])
1159 if (Debug_)
1160 NSLog(@"WB:Debug:Info = %@", [Info_ description]);
1161
1162 [pool release];
1163 }