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