]> git.saurik.com Git - winterboard.git/blob - Library.mm
ebc014083b5ef63e1ce4103eac9ad97cac16e9c4
[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(@"_trace(%u)", __LINE__);
39
40 #include <objc/runtime.h>
41 #include <objc/message.h>
42
43 extern "C" {
44 #include <mach-o/nlist.h>
45 }
46
47 #import <Foundation/Foundation.h>
48 #import <CoreGraphics/CoreGraphics.h>
49
50 #import <UIKit/UIColor.h>
51 #import <UIKit/UIImage.h>
52 #import <UIKit/UIImageView.h>
53 #import <UIKit/UINavigationBarBackground.h>
54
55 #import <UIKit/UIImage-UIImageDeprecated.h>
56
57 #import <UIKit/UIView-Geometry.h>
58 #import <UIKit/UIView-Hierarchy.h>
59 #import <UIKit/UIView-Rendering.h>
60
61 #import <SpringBoard/SBApplication.h>
62 #import <SpringBoard/SBAppWindow.h>
63 #import <SpringBoard/SBButtonBar.h>
64 #import <SpringBoard/SBContentLayer.h>
65 #import <SpringBoard/SBStatusBarContentsView.h>
66 #import <SpringBoard/SBStatusBarTimeView.h>
67 #import <SpringBoard/SBUIController.h>
68
69 #import <CoreGraphics/CGGeometry.h>
70
71 @interface NSDictionary (WinterBoard)
72 - (UIColor *) colorForKey:(NSString *)key;
73 @end
74
75 @implementation NSDictionary (WinterBoard)
76
77 - (UIColor *) colorForKey:(NSString *)key {
78 NSString *value = [self objectForKey:key];
79 if (value == nil)
80 return nil;
81 /* XXX: incorrect */
82 return nil;
83 }
84
85 @end
86
87 /* WinterBoard Backend {{{ */
88 #define WBPrefix "wb_"
89
90 void WBInject(const char *classname, const char *oldname, IMP newimp, const char *type) {
91 Class _class = objc_getClass(classname);
92 if (_class == nil)
93 return;
94 if (!class_addMethod(_class, sel_registerName(oldname), newimp, type))
95 NSLog(@"WB:Error: failed to inject [%s %s]", classname, oldname);
96 }
97
98 void WBRename(const char *classname, const char *oldname, IMP newimp) {
99 Class _class = objc_getClass(classname);
100 if (_class == nil) {
101 NSLog(@"WB:Warning: cannot find class [%s]", classname);
102 return;
103 }
104 Method method = class_getInstanceMethod(_class, sel_getUid(oldname));
105 if (method == nil) {
106 NSLog(@"WB:Warning: cannot find method [%s %s]", classname, oldname);
107 return;
108 }
109 size_t namelen = strlen(oldname);
110 char newname[sizeof(WBPrefix) + namelen];
111 memcpy(newname, WBPrefix, sizeof(WBPrefix) - 1);
112 memcpy(newname + sizeof(WBPrefix) - 1, oldname, namelen + 1);
113 const char *type = method_getTypeEncoding(method);
114 if (!class_addMethod(_class, sel_registerName(newname), method_getImplementation(method), type))
115 NSLog(@"WB:Error: failed to rename [%s %s]", classname, oldname);
116 unsigned int count;
117 Method *methods = class_copyMethodList(_class, &count);
118 for (unsigned int index(0); index != count; ++index)
119 if (methods[index] == method)
120 goto found;
121 if (newimp != NULL)
122 if (!class_addMethod(_class, sel_getUid(oldname), newimp, type))
123 NSLog(@"WB:Error: failed to rename [%s %s]", classname, oldname);
124 goto done;
125 found:
126 if (newimp != NULL)
127 method_setImplementation(method, newimp);
128 done:
129 free(methods);
130 }
131 /* }}} */
132
133 @protocol WinterBoard
134 - (NSString *) wb_pathForIcon;
135 - (NSString *) wb_pathForResource:(NSString *)resource ofType:(NSString *)type;
136 - (id) wb_init;
137 - (id) wb_layer;
138 - (id) wb_initWithSize:(CGSize)size;
139 - (id) wb_initWithFrame:(CGRect)frame;
140 - (id) wb_initWithCoder:(NSCoder *)coder;
141 - (void) wb_setFrame:(CGRect)frame;
142 - (void) wb_setBackgroundColor:(id)color;
143 - (void) wb_setAlpha:(float)value;
144 - (void) wb_setBarStyle:(int)style;
145 - (id) wb_initWithFrame:(CGRect)frame withBarStyle:(int)style withTintColor:(UIColor *)color;
146 - (void) wb_setOpaque:(BOOL)opaque;
147 - (void) wb_didMoveToSuperview;
148 @end
149
150 NSMutableDictionary **ImageMap_;
151
152 bool Debug_;
153
154 NSFileManager *Manager_;
155 NSDictionary *Info_;
156 NSString *theme_;
157 NSString *Wallpaper_;
158
159 NSString *SBApplication$pathForIcon(SBApplication<WinterBoard> *self, SEL sel) {
160 if (theme_ != nil) {
161 NSString *identifier = [self bundleIdentifier];
162
163 #define testForIcon(Name) \
164 if (NSString *name = Name) { \
165 NSString *path = [NSString stringWithFormat:@"%@/Icons/%@.png", theme_, name]; \
166 if ([Manager_ fileExistsAtPath:path]) \
167 return path; \
168 }
169
170 testForIcon([self displayName]);
171 testForIcon(identifier);
172
173 if (identifier != nil) {
174 NSString *path = [NSString stringWithFormat:@"%@/Bundles/%@/icon.png", theme_, identifier];
175 if ([Manager_ fileExistsAtPath:path])
176 return path;
177 }
178 }
179
180 return [self wb_pathForIcon];
181 }
182
183 NSString *NSBundle$pathForResource$ofType$(NSBundle<WinterBoard> *self, SEL sel, NSString *resource, NSString *type) {
184 if (Debug_)
185 NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@.%@\"]", [self bundleIdentifier], resource, type);
186
187 if (theme_ != nil) {
188 NSString *identifier = [self bundleIdentifier];
189
190 if (identifier != nil) {
191 NSString *path = [NSString stringWithFormat:@"%@/Bundles/%@/%@.%@", theme_, identifier, resource, type];
192 if ([Manager_ fileExistsAtPath:path])
193 return path;
194 }
195
196 if ([resource isEqualToString:@"SBDockBG"] && [type isEqualToString:@"png"]) {
197 NSString *path = [NSString stringWithFormat:@"%@/Dock.png", theme_];
198 if ([Manager_ fileExistsAtPath:path])
199 return path;
200 }
201 }
202
203 return [self wb_pathForResource:resource ofType:type];
204 }
205
206 void $setBackgroundColor$(id<WinterBoard> self, SEL sel, UIColor *color) {
207 if (Wallpaper_ != nil)
208 return [self wb_setBackgroundColor:[UIColor clearColor]];
209 return [self wb_setBackgroundColor:color];
210 }
211
212 /*id SBStatusBarContentsView$initWithFrame$(SBStatusBarContentsView<WinterBoard> *self, SEL sel, CGRect frame) {
213 self = [self wb_initWithFrame:frame];
214 if (self == nil)
215 return nil;
216
217 NSString *path = [NSString stringWithFormat:@"%@/StatusBar.png", theme_];
218 if ([Manager_ fileExistsAtPath:path])
219 [self addSubview:[[[UIImageView alloc] initWithImage:[UIImage imageWithContentsOfFile:path]] autorelease]];
220 //[self setBackgroundColor:[UIColor clearColor]];
221
222 return self;
223 }*/
224
225 bool UINavigationBar$setBarStyle$_(SBAppWindow<WinterBoard> *self) {
226 if (Info_ != nil) {
227 NSNumber *number = [Info_ objectForKey:@"NavigationBarStyle"];
228 if (number != nil) {
229 [self wb_setBarStyle:[number intValue]];
230 return true;
231 }
232 }
233
234 return false;
235 }
236
237 /*id UINavigationBarBackground$initWithFrame$withBarStyle$withTintColor$(UINavigationBarBackground<WinterBoard> *self, SEL sel, CGRect frame, int style, UIColor *tint) {
238 _trace();
239
240 if (Info_ != nil) {
241 NSNumber *number = [Info_ objectForKey:@"NavigationBarStyle"];
242 if (number != nil)
243 style = [number intValue];
244
245 UIColor *color = [Info_ colorForKey:@"NavigationBarTint"];
246 if (color != nil)
247 tint = color;
248 }
249
250 return [self wb_initWithFrame:frame withBarStyle:style withTintColor:tint];
251 }*/
252
253 /*id UINavigationBar$initWithCoder$(SBAppWindow<WinterBoard> *self, SEL sel, CGRect frame, NSCoder *coder) {
254 self = [self wb_initWithCoder:coder];
255 if (self == nil)
256 return nil;
257 UINavigationBar$setBarStyle$_(self);
258 return self;
259 }
260
261 id UINavigationBar$initWithFrame$(SBAppWindow<WinterBoard> *self, SEL sel, CGRect frame) {
262 self = [self wb_initWithFrame:frame];
263 if (self == nil)
264 return nil;
265 UINavigationBar$setBarStyle$_(self);
266 return self;
267 }*/
268
269 void UINavigationBar$setBarStyle$(SBAppWindow<WinterBoard> *self, SEL sel, int style) {
270 if (UINavigationBar$setBarStyle$_(self))
271 return;
272 return [self wb_setBarStyle:style];
273 }
274
275 void $didMoveToSuperview(SBButtonBar<WinterBoard> *self, SEL sel) {
276 [[self superview] setBackgroundColor:[UIColor clearColor]];
277 [self wb_didMoveToSuperview];
278 }
279
280 id SBContentLayer$initWithSize$(SBContentLayer<WinterBoard> *self, SEL sel, CGSize size) {
281 self = [self wb_initWithSize:size];
282 if (self == nil)
283 return nil;
284
285 if (Wallpaper_ != nil) {
286 if (UIImage *image = [[UIImage alloc] initWithContentsOfFile:Wallpaper_])
287 [self addSubview:[[[UIImageView alloc] initWithImage:image] autorelease]];
288 [self setBackgroundColor:[UIColor redColor]];
289 }
290
291 return self;
292 }
293
294 extern "C" void FindMappedImages(void);
295 extern "C" NSData *UIImagePNGRepresentation(UIImage *);
296
297 extern "C" void WBInitialize() {
298 NSLog(@"WB:Notice: Installing WinterBoard...");
299
300 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
301
302 struct nlist nl[3];
303 memset(nl, 0, sizeof(nl));
304 nl[0].n_un.n_name = (char *) "___mappedImages";
305 nl[1].n_un.n_name = (char *) "__UISharedImageInitialize";
306 nlist("/System/Library/Frameworks/UIKit.framework/UIKit", nl);
307 ImageMap_ = (id *) nl[0].n_value;
308 void (*__UISharedImageInitialize)(bool) = (void (*)(bool)) nl[1].n_value;
309
310 __UISharedImageInitialize(false);
311
312 /*NSArray *keys = [*ImageMap_ allKeys];
313 for (int i(0), e([keys count]); i != e; ++i) {
314 NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
315 NSString *key = [keys objectAtIndex:i];
316 CGImageRef ref = (CGImageRef) [*ImageMap_ objectForKey:key];
317 UIImage *image = [UIImage imageWithCGImage:ref];
318 NSData *data = UIImagePNGRepresentation(image);
319 [data writeToFile:[NSString stringWithFormat:@"/tmp/pwnr/%@", key] atomically:YES];
320 [pool release];
321 }*/
322
323 Manager_ = [[NSFileManager defaultManager] retain];
324
325 //WBRename("SBStatusBarContentsView", "setBackgroundColor:", (IMP) &$setBackgroundColor$);
326 //WBRename("UINavigationBar", "initWithFrame:", (IMP) &UINavigationBar$initWithFrame$);
327 //WBRename("UINavigationBar", "initWithCoder:", (IMP) &UINavigationBar$initWithCoder$);
328 WBRename("UINavigationBar", "setBarStyle:", (IMP) &UINavigationBar$setBarStyle$);
329 //WBRename("UINavigationBarBackground", "initWithFrame:withBarStyle:withTintColor:", (IMP) &UINavigationBarBackground$initWithFrame$withBarStyle$withTintColor$);
330 //WBRename("SBStatusBarContentsView", "initWithFrame:", (IMP) &SBStatusBarContentsView$initWithFrame$);
331
332 WBRename("SBApplication", "pathForIcon", (IMP) &SBApplication$pathForIcon);
333 WBRename("NSBundle", "pathForResource:ofType:", (IMP) &NSBundle$pathForResource$ofType$);
334 WBRename("SBContentLayer", "initWithSize:", (IMP) &SBContentLayer$initWithSize$);
335 WBRename("SBStatusBarContentsView", "didMoveToSuperview", (IMP) &$didMoveToSuperview);
336 WBRename("SBButtonBar", "didMoveToSuperview", (IMP) &$didMoveToSuperview);
337
338 if (NSDictionary *settings = [[NSDictionary alloc] initWithContentsOfFile:[NSString stringWithFormat:@"%@/Library/Preferences/com.saurik.WinterBoard.plist", NSHomeDirectory()]]) {
339 [settings autorelease];
340 NSString *name = [settings objectForKey:@"Theme"];
341 NSString *path;
342
343 if (theme_ == nil) {
344 path = [NSString stringWithFormat:@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name];
345 if ([Manager_ fileExistsAtPath:path])
346 theme_ = [path retain];
347 }
348
349 if (theme_ == nil) {
350 path = [NSString stringWithFormat:@"/Library/Themes/%@", name];
351 if ([Manager_ fileExistsAtPath:path])
352 theme_ = [path retain];
353 }
354 }
355
356 if (theme_ != nil) {
357 NSString *path = [NSString stringWithFormat:@"%@/Wallpaper.png", theme_];
358 if ([Manager_ fileExistsAtPath:path])
359 Wallpaper_ = [path retain];
360
361 NSString *folder = [NSString stringWithFormat:@"%@/UIImages", theme_];
362 if (NSArray *images = [Manager_ contentsOfDirectoryAtPath:folder error:NULL])
363 for (int i(0), e = [images count]; i != e; ++i) {
364 NSString *name = [images objectAtIndex:i];
365 if (![name hasSuffix:@".png"])
366 continue;
367 NSString *path = [NSString stringWithFormat:@"%@/%@", folder, name];
368 UIImage *image = [UIImage imageWithContentsOfFile:path];
369 [*ImageMap_ setObject:(id)[image imageRef] forKey:name];
370 }
371
372 Info_ = [[NSDictionary alloc] initWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme_]];
373 if (Info_ == nil) {
374 //LabelColor_ = [UIColor whiteColor];
375 } else {
376 //LabelColor_ = [Info_ colorForKey:@"LabelColor"];
377 }
378 }
379
380 [pool release];
381 }