]> git.saurik.com Git - winterboard.git/blob - Library.mm
a6dde911d65c4bc06f04358d7bc95f28008ec7d6
[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 extern "C" {
45 #include <mach-o/nlist.h>
46 }
47
48 #import <Foundation/Foundation.h>
49 #import <CoreGraphics/CoreGraphics.h>
50
51 #import <UIKit/UIColor.h>
52 #import <UIKit/UIFont.h>
53 #import <UIKit/UIImage.h>
54 #import <UIKit/UIImageView.h>
55 #import <UIKit/UINavigationBarBackground.h>
56 #import <UIKit/UIWebDocumentView.h>
57
58 #import <UIKit/NSString-UIStringDrawing.h>
59 #import <UIKit/NSString-UIStringDrawingDeprecated.h>
60
61 #import <UIKit/UIImage-UIImageDeprecated.h>
62
63 #import <UIKit/UIView-Geometry.h>
64 #import <UIKit/UIView-Hierarchy.h>
65 #import <UIKit/UIView-Rendering.h>
66
67 #import <SpringBoard/SBApplication.h>
68 #import <SpringBoard/SBApplicationIcon.h>
69 #import <SpringBoard/SBAppWindow.h>
70 #import <SpringBoard/SBButtonBar.h>
71 #import <SpringBoard/SBContentLayer.h>
72 #import <SpringBoard/SBIconLabel.h>
73 #import <SpringBoard/SBStatusBarContentsView.h>
74 #import <SpringBoard/SBStatusBarTimeView.h>
75 #import <SpringBoard/SBUIController.h>
76
77 #import <CoreGraphics/CGGeometry.h>
78
79 @interface NSDictionary (WinterBoard)
80 - (UIColor *) colorForKey:(NSString *)key;
81 - (BOOL) boolForKey:(NSString *)key;
82 @end
83
84 @implementation NSDictionary (WinterBoard)
85
86 - (UIColor *) colorForKey:(NSString *)key {
87 NSString *value = [self objectForKey:key];
88 if (value == nil)
89 return nil;
90 /* XXX: incorrect */
91 return nil;
92 }
93
94 - (BOOL) boolForKey:(NSString *)key {
95 if (NSString *value = [self objectForKey:key])
96 return [value boolValue];
97 return NO;
98 }
99
100 @end
101
102 bool Debug_ = false;
103 bool Engineer_ = false;
104
105 /* WinterBoard Backend {{{ */
106 #define WBPrefix "wb_"
107
108 void WBInject(const char *classname, const char *oldname, IMP newimp, const char *type) {
109 Class _class = objc_getClass(classname);
110 if (_class == nil)
111 return;
112 if (!class_addMethod(_class, sel_registerName(oldname), newimp, type))
113 NSLog(@"WB:Error: failed to inject [%s %s]", classname, oldname);
114 }
115
116 void WBRename(bool instance, const char *classname, const char *oldname, IMP newimp) {
117 Class _class = objc_getClass(classname);
118 if (_class == nil) {
119 if (Debug_)
120 NSLog(@"WB:Warning: cannot find class [%s]", classname);
121 return;
122 }
123 if (!instance)
124 _class = object_getClass(_class);
125 Method method = class_getInstanceMethod(_class, sel_getUid(oldname));
126 if (method == nil) {
127 if (Debug_)
128 NSLog(@"WB:Warning: cannot find method [%s %s]", classname, oldname);
129 return;
130 }
131 size_t namelen = strlen(oldname);
132 char newname[sizeof(WBPrefix) + namelen];
133 memcpy(newname, WBPrefix, sizeof(WBPrefix) - 1);
134 memcpy(newname + sizeof(WBPrefix) - 1, oldname, namelen + 1);
135 const char *type = method_getTypeEncoding(method);
136 if (!class_addMethod(_class, sel_registerName(newname), method_getImplementation(method), type))
137 NSLog(@"WB:Error: failed to rename [%s %s]", classname, oldname);
138 unsigned int count;
139 Method *methods = class_copyMethodList(_class, &count);
140 for (unsigned int index(0); index != count; ++index)
141 if (methods[index] == method)
142 goto found;
143 if (newimp != NULL)
144 if (!class_addMethod(_class, sel_getUid(oldname), newimp, type))
145 NSLog(@"WB:Error: failed to rename [%s %s]", classname, oldname);
146 goto done;
147 found:
148 if (newimp != NULL)
149 method_setImplementation(method, newimp);
150 done:
151 free(methods);
152 }
153 /* }}} */
154
155 @protocol WinterBoard
156 - (NSString *) wb_pathForIcon;
157 - (NSString *) wb_pathForResource:(NSString *)resource ofType:(NSString *)type;
158 - (id) wb_init;
159 - (id) wb_layer;
160 - (id) wb_initWithSize:(CGSize)size;
161 - (id) wb_initWithSize:(CGSize)size label:(NSString *)label;
162 - (id) wb_initWithFrame:(CGRect)frame;
163 - (id) wb_initWithCoder:(NSCoder *)coder;
164 - (void) wb_setFrame:(CGRect)frame;
165 - (void) wb_drawRect:(CGRect)rect;
166 - (void) wb_setBackgroundColor:(id)color;
167 - (void) wb_setAlpha:(float)value;
168 - (void) wb_setBarStyle:(int)style;
169 - (id) wb_initWithFrame:(CGRect)frame withBarStyle:(int)style withTintColor:(UIColor *)color;
170 - (void) wb_setOpaque:(BOOL)opaque;
171 - (void) wb_setInDock:(BOOL)docked;
172 - (void) wb_didMoveToSuperview;
173 + (UIImage *) wb_imageNamed:(NSString *)name inBundle:(NSBundle *)bundle;
174 - (NSDictionary *) wb_infoDictionary;
175 - (UIImage *) wb_icon;
176 @end
177
178 NSMutableDictionary **ImageMap_;
179
180 NSFileManager *Manager_;
181 NSDictionary *English_;
182 NSDictionary *Info_;
183 NSString *theme_;
184
185 NSString *$pathForIcon$(SBApplication<WinterBoard> *self) {
186 NSString *identifier = [self bundleIdentifier];
187
188 #define testForIcon(Name) \
189 if (NSString *name = Name) { \
190 NSString *path = [NSString stringWithFormat:@"%@/Icons/%@.png", theme_, name]; \
191 if ([Manager_ fileExistsAtPath:path]) \
192 return path; \
193 }
194
195 if (identifier != nil) {
196 NSString *path = [NSString stringWithFormat:@"%@/Bundles/%@/icon.png", theme_, identifier];
197 if ([Manager_ fileExistsAtPath:path])
198 return path;
199 }
200
201 if (NSString *folder = [[self path] lastPathComponent]) {
202 NSString *path = [NSString stringWithFormat:@"%@/Folders/%@/icon.png", theme_, folder];
203 if ([Manager_ fileExistsAtPath:path])
204 return path;
205 }
206
207 testForIcon(identifier);
208 testForIcon([self displayName]);
209
210 if (NSString *display = [self displayIdentifier])
211 testForIcon([English_ objectForKey:display]);
212
213 return nil;
214 }
215
216 static UIImage *SBApplicationIcon$icon(SBApplicationIcon<WinterBoard> *self, SEL sel) {
217 if (NSString *path = $pathForIcon$([self application]))
218 return [UIImage imageWithContentsOfFile:path];
219 return [self wb_icon];
220 }
221
222 static NSString *SBApplication$pathForIcon(SBApplication<WinterBoard> *self, SEL sel) {
223 if (theme_ != nil)
224 if (NSString *path = $pathForIcon$(self))
225 return path;
226
227 return [self wb_pathForIcon];
228 }
229
230 static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle) {
231 if (theme_ != nil) {
232 NSString *identifier = [bundle bundleIdentifier];
233
234 if (identifier != nil) {
235 NSString *path = [NSString stringWithFormat:@"%@/Bundles/%@/%@", theme_, identifier, file];
236 if ([Manager_ fileExistsAtPath:path])
237 return path;
238 }
239
240 if (NSString *folder = [[bundle bundlePath] lastPathComponent]) {
241 NSString *path = [NSString stringWithFormat:@"%@/Folders/%@/%@", theme_, folder, file];
242 if ([Manager_ fileExistsAtPath:path])
243 return path;
244 }
245
246 #define remapResourceName(oldname, newname) \
247 else if ([file isEqualToString:oldname]) { \
248 NSString *path = [NSString stringWithFormat:@"%@/%@.png", theme_, newname]; \
249 if ([Manager_ fileExistsAtPath:path]) \
250 return path; \
251 }
252
253 if (identifier == nil || ![identifier isEqualToString:@"com.apple.springboard"]);
254 remapResourceName(@"FSO_BG.png", @"StatusBar")
255 remapResourceName(@"SBDockBG.png", @"Dock")
256 remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather")
257 }
258
259 return nil;
260 }
261
262 static UIImage *UIImage$imageNamed$inBundle$(Class<WinterBoard> self, SEL sel, NSString *name, NSBundle *bundle) {
263 if (Debug_)
264 NSLog(@"WB:Debug: [UIImage(%@) imageNamed:\"%@\"]", [bundle bundleIdentifier], name);
265 if (NSString *path = $pathForFile$inBundle$(name, bundle))
266 return [UIImage imageWithContentsOfFile:path];
267 return [self wb_imageNamed:name inBundle:bundle];
268 }
269
270 static UIImage *UIImage$imageNamed$(Class<WinterBoard> self, SEL sel, NSString *name) {
271 return UIImage$imageNamed$inBundle$(self, sel, name, [NSBundle mainBundle]);
272 }
273
274 static NSString *NSBundle$pathForResource$ofType$(NSBundle<WinterBoard> *self, SEL sel, NSString *resource, NSString *type) {
275 NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type];
276 if (Debug_)
277 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file);
278 if (NSString *path = $pathForFile$inBundle$(file, self))
279 return path;
280 return [self wb_pathForResource:resource ofType:type];
281 }
282
283 bool UINavigationBar$setBarStyle$_(SBAppWindow<WinterBoard> *self) {
284 if (Info_ != nil) {
285 NSNumber *number = [Info_ objectForKey:@"NavigationBarStyle"];
286 if (number != nil) {
287 [self wb_setBarStyle:[number intValue]];
288 return true;
289 }
290 }
291
292 return false;
293 }
294
295 /*id UINavigationBarBackground$initWithFrame$withBarStyle$withTintColor$(UINavigationBarBackground<WinterBoard> *self, SEL sel, CGRect frame, int style, UIColor *tint) {
296 _trace();
297
298 if (Info_ != nil) {
299 NSNumber *number = [Info_ objectForKey:@"NavigationBarStyle"];
300 if (number != nil)
301 style = [number intValue];
302
303 UIColor *color = [Info_ colorForKey:@"NavigationBarTint"];
304 if (color != nil)
305 tint = color;
306 }
307
308 return [self wb_initWithFrame:frame withBarStyle:style withTintColor:tint];
309 }*/
310
311 /*id UINavigationBar$initWithCoder$(SBAppWindow<WinterBoard> *self, SEL sel, CGRect frame, NSCoder *coder) {
312 self = [self wb_initWithCoder:coder];
313 if (self == nil)
314 return nil;
315 UINavigationBar$setBarStyle$_(self);
316 return self;
317 }
318
319 id UINavigationBar$initWithFrame$(SBAppWindow<WinterBoard> *self, SEL sel, CGRect frame) {
320 self = [self wb_initWithFrame:frame];
321 if (self == nil)
322 return nil;
323 UINavigationBar$setBarStyle$_(self);
324 return self;
325 }*/
326
327 static void UINavigationBar$setBarStyle$(SBAppWindow<WinterBoard> *self, SEL sel, int style) {
328 if (UINavigationBar$setBarStyle$_(self))
329 return;
330 return [self wb_setBarStyle:style];
331 }
332
333 static void $didMoveToSuperview(SBButtonBar<WinterBoard> *self, SEL sel) {
334 [[self superview] setBackgroundColor:[UIColor clearColor]];
335 [self wb_didMoveToSuperview];
336 }
337
338 static NSString *$getTheme$(NSString *file) {
339 NSString *path([NSString stringWithFormat:@"%@/%@", theme_, file]);
340 return [Manager_ fileExistsAtPath:path] ? path : nil;
341 }
342
343 static id SBContentLayer$initWithSize$(SBContentLayer<WinterBoard> *self, SEL sel, CGSize size) {
344 self = [self wb_initWithSize:size];
345 if (self == nil)
346 return nil;
347
348 if (NSString *path = $getTheme$(@"Wallpaper.png"))
349 if (UIImage *image = [[[UIImage alloc] initWithContentsOfFile:path] autorelease])
350 [self addSubview:[[[UIImageView alloc] initWithImage:image] autorelease]];
351 if (NSString *path = $getTheme$(@"Wallpaper.html")) {
352 CGRect bounds = [self bounds];
353
354 UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]);
355 [view setAutoresizes:YES];
356
357 [view loadRequest:[NSURLRequest requestWithURL:[NSURL fileURLWithPath:path]]];
358
359 [[view webView] setDrawsBackground:NO];
360 [view setBackgroundColor:[UIColor clearColor]];
361
362 [self addSubview:view];
363 }
364
365 return self;
366 }
367
368 #define WBDelegate(delegate) \
369 - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \
370 if (Engineer_) \
371 NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \
372 if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \
373 return sig; \
374 NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \
375 return nil; \
376 } \
377 \
378 - (void) forwardInvocation:(NSInvocation*)inv { \
379 SEL sel = [inv selector]; \
380 if ([delegate respondsToSelector:sel]) \
381 [inv invokeWithTarget:delegate]; \
382 else \
383 NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \
384 }
385
386 static unsigned *ContextCount_;
387 static void ***ContextStack_;
388
389 extern "C" CGColorRef CGGStateGetSystemColor(void *);
390 extern "C" CGColorRef CGGStateGetFillColor(void *);
391 extern "C" CGColorRef CGGStateGetStrokeColor(void *);
392 extern "C" NSString *UIStyleStringFromColor(CGColorRef);
393
394 @interface WBTime : NSProxy {
395 NSString *time_;
396 _transient SBStatusBarTimeView *view_;
397 }
398
399 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view;
400
401 @end
402
403 @implementation WBTime
404
405 - (void) dealloc {
406 [time_ release];
407 [super dealloc];
408 }
409
410 - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view {
411 time_ = [time retain];
412 view_ = view;
413 return self;
414 }
415
416 WBDelegate(time_)
417
418 - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode {
419 if (Info_ != nil)
420 if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) {
421 BOOL mode;
422 object_getInstanceVariable(view_, "_mode", (void **) &mode);
423
424 [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@""
425 "font-family: Helvetica; "
426 "font-weight: bold; "
427 "font-size: 14px; "
428 "color: %@; "
429 "%@", mode ? @"white" : @"black", custom]];
430
431 return CGSizeZero;
432 }
433
434 return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode];
435 }
436
437 @end
438
439 @interface WBIconLabel : NSProxy {
440 NSString *string_;
441 BOOL docked_;
442 }
443
444 - (id) initWithString:(NSString *)string;
445
446 @end
447
448 @implementation WBIconLabel
449
450 - (void) dealloc {
451 [string_ release];
452 [super dealloc];
453 }
454
455 - (id) initWithString:(NSString *)string {
456 string_ = [string retain];
457 return self;
458 }
459
460 WBDelegate(string_)
461
462 - (NSString *) _iconLabelStyle {
463 return Info_ == nil ? nil : [Info_ objectForKey:(docked_ ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")];
464 }
465
466 - (CGSize) drawInRect:(CGRect)rect withFont:(UIFont *)font lineBreakMode:(int)mode alignment:(int)alignment {
467 if (NSString *custom = [self _iconLabelStyle]) {
468 [string_ drawInRect:rect withStyle:[NSString stringWithFormat:@""
469 "font-family: Helvetica; "
470 "font-weight: bold; "
471 "font-size: 11px; "
472 "text-align: center; "
473 "color: %@; "
474 "%@", docked_ ? @"white" : @"#b3b3b3", custom]];
475
476 return CGSizeZero;
477 }
478
479 return [string_ drawInRect:rect withFont:font lineBreakMode:mode alignment:alignment];
480 }
481
482 - (void) drawInRect:(CGRect)rect withStyle:(NSString *)style {
483 if (NSString *custom = [self _iconLabelStyle])
484 return [string_ drawInRect:rect withStyle:[NSString stringWithFormat:@"%@; %@", style, custom]];
485 return [string_ drawInRect:rect withStyle:style];
486 }
487
488 - (BOOL) respondsToSelector:(SEL)sel {
489 return
490 sel == @selector(setInDock:)
491 ? YES : [super respondsToSelector:sel];
492 }
493
494 - (void) setInDock:(BOOL)docked {
495 docked_ = docked;
496 }
497
498 @end
499
500 static void SBStatusBarTimeView$drawRect$(SBStatusBarTimeView<WinterBoard> *self, SEL sel, CGRect rect) {
501 id time;
502 object_getInstanceVariable(self, "_time", (void **) &time);
503 if (time != nil && [time class] != [WBTime class])
504 object_setInstanceVariable(self, "_time", (void *) [[WBTime alloc] initWithTime:[time autorelease] view:self]);
505 return [self wb_drawRect:rect];
506 }
507
508 static void SBIconLabel$setInDock$(SBIconLabel<WinterBoard> *self, SEL sel, BOOL docked) {
509 id label;
510 object_getInstanceVariable(self, "_label", (void **) &label);
511 if (Info_ == nil || [Info_ boolForKey:@"IconLabelInDock"])
512 docked = YES;
513 if (label != nil && [label respondsToSelector:@selector(setInDock:)])
514 [label setInDock:docked];
515 return [self wb_setInDock:docked];
516 }
517
518 static id SBIconLabel$initWithSize$label$(SBIconLabel<WinterBoard> *self, SEL sel, CGSize size, NSString *label) {
519 // XXX: technically I'm misusing self here
520 return [self wb_initWithSize:size label:[[[WBIconLabel alloc] initWithString:label] autorelease]];
521 //return [self wb_initWithSize:size label:label];
522 }
523
524 extern "C" void FindMappedImages(void);
525 extern "C" NSData *UIImagePNGRepresentation(UIImage *);
526
527 static void (*__UISharedImageInitialize)(bool);
528
529 extern "C" void WBInitialize() {
530 NSLog(@"WB:Notice: Installing WinterBoard...");
531
532 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
533
534 struct nlist nl[5];
535 memset(nl, 0, sizeof(nl));
536
537 nl[0].n_un.n_name = (char *) "___mappedImages";
538 nl[1].n_un.n_name = (char *) "__UISharedImageInitialize";
539 nl[2].n_un.n_name = (char *) "___currentContextCount";
540 nl[3].n_un.n_name = (char *) "___currentContextStack";
541
542 nlist("/System/Library/Frameworks/UIKit.framework/UIKit", nl);
543
544 ImageMap_ = (id *) nl[0].n_value;
545 __UISharedImageInitialize = (void (*)(bool)) nl[1].n_value;
546 ContextCount_ = (unsigned *) nl[2].n_value;
547 ContextStack_ = (void ***) nl[3].n_value;
548
549 __UISharedImageInitialize(false);
550
551 English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"];
552 if (English_ != nil)
553 English_ = [English_ retain];
554
555 Manager_ = [[NSFileManager defaultManager] retain];
556
557 //WBRename("UINavigationBar", "initWithCoder:", (IMP) &UINavigationBar$initWithCoder$);
558 WBRename(true, "UINavigationBar", "setBarStyle:", (IMP) &UINavigationBar$setBarStyle$);
559 //WBRename("UINavigationBarBackground", "initWithFrame:withBarStyle:withTintColor:", (IMP) &UINavigationBarBackground$initWithFrame$withBarStyle$withTintColor$);
560
561 WBRename(false, "UIImage", "imageNamed:inBundle:", (IMP) &UIImage$imageNamed$inBundle$);
562 WBRename(false, "UIImage", "imageNamed:", (IMP) &UIImage$imageNamed$);
563 WBRename(true, "SBApplicationIcon", "icon", (IMP) &SBApplicationIcon$icon);
564 WBRename(true, "SBApplication", "pathForIcon", (IMP) &SBApplication$pathForIcon);
565 WBRename(true, "NSBundle", "pathForResource:ofType:", (IMP) &NSBundle$pathForResource$ofType$);
566 WBRename(true, "SBContentLayer", "initWithSize:", (IMP) &SBContentLayer$initWithSize$);
567 WBRename(true, "SBStatusBarContentsView", "didMoveToSuperview", (IMP) &$didMoveToSuperview);
568 WBRename(true, "SBButtonBar", "didMoveToSuperview", (IMP) &$didMoveToSuperview);
569 WBRename(true, "SBIconLabel", "setInDock:", (IMP) &SBIconLabel$setInDock$);
570 WBRename(true, "SBIconLabel", "initWithSize:label:", (IMP) &SBIconLabel$initWithSize$label$);
571 WBRename(true, "SBStatusBarTimeView", "drawRect:", (IMP) &SBStatusBarTimeView$drawRect$);
572
573 if (NSDictionary *settings = [[NSDictionary alloc] initWithContentsOfFile:[NSString stringWithFormat:@"%@/Library/Preferences/com.saurik.WinterBoard.plist", NSHomeDirectory()]]) {
574 [settings autorelease];
575 NSString *name = [settings objectForKey:@"Theme"];
576 NSString *path;
577
578 if (theme_ == nil) {
579 path = [NSString stringWithFormat:@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name];
580 if ([Manager_ fileExistsAtPath:path])
581 theme_ = [path retain];
582 }
583
584 if (theme_ == nil) {
585 path = [NSString stringWithFormat:@"/Library/Themes/%@", name];
586 if ([Manager_ fileExistsAtPath:path])
587 theme_ = [path retain];
588 }
589 }
590
591 if (theme_ != nil) {
592 NSString *folder = [NSString stringWithFormat:@"%@/UIImages", theme_];
593 if (NSArray *images = [Manager_ contentsOfDirectoryAtPath:folder error:NULL])
594 for (int i(0), e = [images count]; i != e; ++i) {
595 NSString *name = [images objectAtIndex:i];
596 if (![name hasSuffix:@".png"])
597 continue;
598 NSString *path = [NSString stringWithFormat:@"%@/%@", folder, name];
599 UIImage *image = [UIImage imageWithContentsOfFile:path];
600 [*ImageMap_ setObject:(id)[image imageRef] forKey:name];
601 }
602
603 Info_ = [[NSDictionary alloc] initWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme_]];
604 }
605
606 [pool release];
607 }