]>
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 | ||
62b2dbad JF |
38 | #define _trace() NSLog(@"_trace(%u)", __LINE__); |
39 | ||
d5168fd6 JF |
40 | #include <objc/runtime.h> |
41 | #include <objc/message.h> | |
42 | ||
43 | #import <Foundation/Foundation.h> | |
44 | ||
45 | #import <UIKit/UIColor.h> | |
46 | #import <UIKit/UIImage.h> | |
47 | #import <UIKit/UIImageView.h> | |
26c43b47 | 48 | #import <UIKit/UINavigationBarBackground.h> |
62b2dbad JF |
49 | |
50 | #import <UIKit/UIView-Geometry.h> | |
d5168fd6 | 51 | #import <UIKit/UIView-Hierarchy.h> |
62b2dbad | 52 | #import <UIKit/UIView-Rendering.h> |
d5168fd6 JF |
53 | |
54 | #import <SpringBoard/SBApplication.h> | |
55 | #import <SpringBoard/SBAppWindow.h> | |
62b2dbad | 56 | #import <SpringBoard/SBButtonBar.h> |
d5168fd6 JF |
57 | #import <SpringBoard/SBContentLayer.h> |
58 | #import <SpringBoard/SBUIController.h> | |
59 | ||
60 | #import <CoreGraphics/CGGeometry.h> | |
61 | ||
26c43b47 JF |
62 | @interface NSDictionary (WinterBoard) |
63 | - (UIColor *) colorForKey:(NSString *)key; | |
64 | @end | |
65 | ||
66 | @implementation NSDictionary (WinterBoard) | |
67 | ||
68 | - (UIColor *) colorForKey:(NSString *)key { | |
69 | NSString *value = [self objectForKey:key]; | |
70 | if (value == nil) | |
71 | return nil; | |
72 | /* XXX: incorrect */ | |
73 | return nil; | |
74 | } | |
75 | ||
76 | @end | |
77 | ||
d5168fd6 JF |
78 | /* WinterBoard Backend {{{ */ |
79 | #define WBPrefix "wb_" | |
80 | ||
81 | void WBInject(const char *classname, const char *oldname, IMP newimp, const char *type) { | |
82 | Class _class = objc_getClass(classname); | |
83 | if (_class == nil) | |
84 | return; | |
85 | if (!class_addMethod(_class, sel_registerName(oldname), newimp, type)) | |
86 | NSLog(@"WB: failed to inject [%s %s]", classname, oldname); | |
87 | } | |
88 | ||
89 | void WBRename(const char *classname, const char *oldname, IMP newimp) { | |
90 | Class _class = objc_getClass(classname); | |
26c43b47 JF |
91 | if (_class == nil) { |
92 | NSLog(@"WB: cannot find class [%s]", classname); | |
93 | return; | |
94 | } | |
95 | Method method = class_getInstanceMethod(_class, sel_getUid(oldname)); | |
96 | if (method == nil) { | |
97 | NSLog(@"WB: cannot find method [%s %s]", classname, oldname); | |
d5168fd6 | 98 | return; |
26c43b47 | 99 | } |
d5168fd6 JF |
100 | size_t namelen = strlen(oldname); |
101 | char newname[sizeof(WBPrefix) + namelen]; | |
102 | memcpy(newname, WBPrefix, sizeof(WBPrefix) - 1); | |
103 | memcpy(newname + sizeof(WBPrefix) - 1, oldname, namelen + 1); | |
d5168fd6 JF |
104 | const char *type = method_getTypeEncoding(method); |
105 | if (!class_addMethod(_class, sel_registerName(newname), method_getImplementation(method), type)) | |
106 | NSLog(@"WB: failed to rename [%s %s]", classname, oldname); | |
107 | unsigned int count; | |
108 | Method *methods = class_copyMethodList(_class, &count); | |
109 | for (unsigned int index(0); index != count; ++index) | |
110 | if (methods[index] == method) | |
111 | goto found; | |
112 | if (newimp != NULL) | |
113 | if (!class_addMethod(_class, sel_getUid(oldname), newimp, type)) | |
114 | NSLog(@"WB: failed to rename [%s %s]", classname, oldname); | |
115 | goto done; | |
116 | found: | |
117 | if (newimp != NULL) | |
118 | method_setImplementation(method, newimp); | |
119 | done: | |
120 | free(methods); | |
121 | } | |
d5168fd6 JF |
122 | /* }}} */ |
123 | ||
124 | @protocol WinterBoard | |
125 | - (NSString *) wb_pathForIcon; | |
126 | - (NSString *) wb_pathForResource:(NSString *)resource ofType:(NSString *)type; | |
127 | - (id) wb_initWithSize:(CGSize)size; | |
62b2dbad | 128 | - (id) wb_initWithFrame:(CGRect)frame; |
26c43b47 | 129 | - (id) wb_initWithCoder:(NSCoder *)coder; |
62b2dbad | 130 | - (void) wb_setFrame:(CGRect)frame; |
d5168fd6 | 131 | - (void) wb_setBackgroundColor:(id)color; |
62b2dbad | 132 | - (void) wb_setAlpha:(float)value; |
26c43b47 JF |
133 | - (void) wb_setBarStyle:(int)style; |
134 | - (id) wb_initWithFrame:(CGRect)frame withBarStyle:(int)style withTintColor:(UIColor *)color; | |
d5168fd6 JF |
135 | @end |
136 | ||
26c43b47 JF |
137 | NSFileManager *Manager_; |
138 | NSDictionary *Info_; | |
62b2dbad JF |
139 | NSString *theme_; |
140 | NSString *Wallpaper_; | |
d5168fd6 JF |
141 | |
142 | NSString *SBApplication$pathForIcon(SBApplication<WinterBoard> *self, SEL sel) { | |
62b2dbad | 143 | if (theme_ != nil) { |
26c43b47 | 144 | NSString *identifier = [self bundleIdentifier]; |
62b2dbad JF |
145 | |
146 | #define testForIcon(Name) \ | |
147 | if (NSString *name = Name) { \ | |
26c43b47 JF |
148 | NSString *path = [NSString stringWithFormat:@"%@/Icons/%@.png", theme_, name]; \ |
149 | if ([Manager_ fileExistsAtPath:path]) \ | |
62b2dbad JF |
150 | return path; \ |
151 | } | |
152 | ||
153 | testForIcon([self displayName]); | |
26c43b47 JF |
154 | testForIcon(identifier); |
155 | ||
156 | if (identifier != nil) { | |
157 | NSString *path = [NSString stringWithFormat:@"%@/Bundles/%@/icon.png", theme_, identifier]; | |
158 | if ([Manager_ fileExistsAtPath:path]) | |
159 | return path; | |
160 | } | |
62b2dbad JF |
161 | } |
162 | ||
d5168fd6 JF |
163 | return [self wb_pathForIcon]; |
164 | } | |
165 | ||
166 | NSString *NSBundle$pathForResource$ofType$(NSBundle<WinterBoard> *self, SEL sel, NSString *resource, NSString *type) { | |
26c43b47 JF |
167 | NSLog(@"WB: NSBundle(%@) pathForResource:%@ ofType:%@", [self bundleIdentifier], resource, type); |
168 | ||
169 | if (theme_ != nil) { | |
170 | NSString *identifier = [self bundleIdentifier]; | |
171 | ||
172 | if (identifier != nil) { | |
173 | NSString *path = [NSString stringWithFormat:@"%@/Bundles/%@/%@.%@", theme_, identifier, resource, type]; | |
174 | if ([Manager_ fileExistsAtPath:path]) | |
175 | return path; | |
176 | NSLog(@"p...%@ (%u)", path, [Manager_ fileExistsAtPath:path]); | |
177 | } | |
178 | ||
179 | if ([resource isEqualToString:@"SBDockBG"] && [type isEqualToString:@"png"]) { | |
180 | NSString *path = [NSString stringWithFormat:@"%@/Dock.png", theme_]; | |
181 | if ([Manager_ fileExistsAtPath:path]) | |
182 | return path; | |
183 | } | |
d5168fd6 JF |
184 | } |
185 | ||
186 | return [self wb_pathForResource:resource ofType:type]; | |
187 | } | |
188 | ||
62b2dbad JF |
189 | void SBAppWindow$setBackgroundColor$(SBAppWindow<WinterBoard> *self, SEL sel, UIColor *color) { |
190 | if (Wallpaper_ != nil) | |
191 | return [self wb_setBackgroundColor:[UIColor clearColor]]; | |
192 | return [self wb_setBackgroundColor:color]; | |
d5168fd6 JF |
193 | } |
194 | ||
26c43b47 JF |
195 | bool UINavigationBar$setBarStyle$_(SBAppWindow<WinterBoard> *self) { |
196 | if (Info_ != nil) { | |
197 | NSNumber *number = [Info_ objectForKey:@"NavigationBarStyle"]; | |
198 | if (number != nil) { | |
199 | [self wb_setBarStyle:[number intValue]]; | |
200 | return true; | |
201 | } | |
202 | } | |
203 | ||
204 | return false; | |
205 | } | |
206 | ||
207 | /*id UINavigationBarBackground$initWithFrame$withBarStyle$withTintColor$(UINavigationBarBackground<WinterBoard> *self, SEL sel, CGRect frame, int style, UIColor *tint) { | |
208 | _trace(); | |
209 | ||
210 | if (Info_ != nil) { | |
211 | NSNumber *number = [Info_ objectForKey:@"NavigationBarStyle"]; | |
212 | if (number != nil) | |
213 | style = [number intValue]; | |
214 | ||
215 | UIColor *color = [Info_ colorForKey:@"NavigationBarTint"]; | |
216 | if (color != nil) | |
217 | tint = color; | |
218 | } | |
219 | ||
220 | return [self wb_initWithFrame:frame withBarStyle:style withTintColor:tint]; | |
221 | }*/ | |
222 | ||
223 | /*id UINavigationBar$initWithCoder$(SBAppWindow<WinterBoard> *self, SEL sel, CGRect frame, NSCoder *coder) { | |
224 | self = [self wb_initWithCoder:coder]; | |
225 | if (self == nil) | |
226 | return nil; | |
227 | UINavigationBar$setBarStyle$_(self); | |
228 | return self; | |
229 | } | |
230 | ||
231 | id UINavigationBar$initWithFrame$(SBAppWindow<WinterBoard> *self, SEL sel, CGRect frame) { | |
232 | self = [self wb_initWithFrame:frame]; | |
233 | if (self == nil) | |
234 | return nil; | |
235 | UINavigationBar$setBarStyle$_(self); | |
236 | return self; | |
237 | }*/ | |
238 | ||
239 | void UINavigationBar$setBarStyle$(SBAppWindow<WinterBoard> *self, SEL sel, int style) { | |
240 | if (UINavigationBar$setBarStyle$_(self)) | |
241 | return; | |
242 | return [self wb_setBarStyle:style]; | |
243 | } | |
244 | ||
62b2dbad JF |
245 | /*id SBButtonBar$initWithFrame$(SBButtonBar<WinterBoard> *self, SEL sel, CGRect frame) { |
246 | self = [self wb_initWithFrame:frame]; | |
247 | if (self == nil) | |
248 | return nil; | |
249 | if (Wallpaper_ != nil) | |
250 | [self setBackgroundColor:[UIColor clearColor]]; | |
251 | return self; | |
252 | }*/ | |
253 | ||
d5168fd6 JF |
254 | id SBContentLayer$initWithSize$(SBContentLayer<WinterBoard> *self, SEL sel, CGSize size) { |
255 | self = [self wb_initWithSize:size]; | |
256 | if (self == nil) | |
257 | return nil; | |
258 | ||
62b2dbad JF |
259 | if (Wallpaper_ != nil) |
260 | if (UIImage *image = [[UIImage alloc] initWithContentsOfFile:Wallpaper_]) | |
261 | [self addSubview:[[[UIImageView alloc] initWithImage:image] autorelease]]; | |
d5168fd6 JF |
262 | |
263 | return self; | |
264 | } | |
265 | ||
266 | extern "C" void WBInitialize() { | |
d5168fd6 JF |
267 | NSLog(@"WB: installing WinterBoard..."); |
268 | ||
269 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | |
270 | ||
d5168fd6 JF |
271 | WBRename("SBApplication", "pathForIcon", (IMP) &SBApplication$pathForIcon); |
272 | WBRename("NSBundle", "pathForResource:ofType:", (IMP) &NSBundle$pathForResource$ofType$); | |
273 | WBRename("SBAppWindow", "setBackgroundColor:", (IMP) &SBAppWindow$setBackgroundColor$); | |
274 | WBRename("SBContentLayer", "initWithSize:", (IMP) &SBContentLayer$initWithSize$); | |
26c43b47 JF |
275 | //WBRename("UINavigationBar", "initWithFrame:", (IMP) &UINavigationBar$initWithFrame$); |
276 | //WBRename("UINavigationBar", "initWithCoder:", (IMP) &UINavigationBar$initWithCoder$); | |
277 | WBRename("UINavigationBar", "setBarStyle:", (IMP) &UINavigationBar$setBarStyle$); | |
278 | //WBRename("UINavigationBarBackground", "initWithFrame:withBarStyle:withTintColor:", (IMP) &UINavigationBarBackground$initWithFrame$withBarStyle$withTintColor$); | |
279 | ||
280 | Manager_ = [[NSFileManager defaultManager] retain]; | |
d5168fd6 | 281 | |
62b2dbad JF |
282 | if (NSDictionary *settings = [[NSDictionary alloc] initWithContentsOfFile:[NSString stringWithFormat:@"%@/Library/Preferences/com.saurik.WinterBoard.plist", NSHomeDirectory()]]) { |
283 | [settings autorelease]; | |
26c43b47 JF |
284 | NSString *name = [settings objectForKey:@"Theme"]; |
285 | NSString *path; | |
62b2dbad | 286 | |
26c43b47 JF |
287 | if (theme_ == nil) { |
288 | path = [NSString stringWithFormat:@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name]; | |
289 | if ([Manager_ fileExistsAtPath:path]) | |
290 | theme_ = [path retain]; | |
291 | } | |
292 | ||
293 | if (theme_ == nil) { | |
294 | path = [NSString stringWithFormat:@"/Library/Themes/%@", name]; | |
295 | if ([Manager_ fileExistsAtPath:path]) | |
296 | theme_ = [path retain]; | |
297 | } | |
298 | } | |
299 | ||
300 | if (theme_ != nil) { | |
301 | NSString *path = [NSString stringWithFormat:@"%@/Wallpaper.png", theme_]; | |
302 | if ([Manager_ fileExistsAtPath:path]) | |
62b2dbad | 303 | Wallpaper_ = [path retain]; |
26c43b47 JF |
304 | |
305 | Info_ = [[NSDictionary alloc] initWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme_]]; | |
306 | if (Info_ == nil) { | |
307 | //LabelColor_ = [UIColor whiteColor]; | |
308 | } else { | |
309 | //LabelColor_ = [Info_ colorForKey:@"LabelColor"]; | |
310 | } | |
62b2dbad JF |
311 | } |
312 | ||
d5168fd6 JF |
313 | [pool release]; |
314 | } |