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