]> git.saurik.com Git - winterboard.git/blame - Library.mm
Added fully general theme support.
[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
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
81void 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
89void 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
137NSFileManager *Manager_;
138NSDictionary *Info_;
62b2dbad
JF
139NSString *theme_;
140NSString *Wallpaper_;
d5168fd6
JF
141
142NSString *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
166NSString *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
189void 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
195bool 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
231id 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
239void 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
254id 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
266extern "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}