]>
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 | |
e6f0817b | 41 | #include <substrate.h> |
95a5777b | 42 | |
e6f0817b | 43 | #import <CoreFoundation/CoreFoundation.h> |
d5168fd6 | 44 | #import <Foundation/Foundation.h> |
2435118f | 45 | #import <CoreGraphics/CoreGraphics.h> |
d5168fd6 JF |
46 | |
47 | #import <UIKit/UIColor.h> | |
889cb4f2 | 48 | #import <UIKit/UIFont.h> |
d5168fd6 JF |
49 | #import <UIKit/UIImage.h> |
50 | #import <UIKit/UIImageView.h> | |
95a5777b | 51 | #import <UIKit/UINavigationBar.h> |
26c43b47 | 52 | #import <UIKit/UINavigationBarBackground.h> |
95a5777b | 53 | #import <UIKit/UIToolbar.h> |
394d1eb5 | 54 | #import <UIKit/UIWebDocumentView.h> |
62b2dbad | 55 | |
889cb4f2 JF |
56 | #import <UIKit/NSString-UIStringDrawing.h> |
57 | #import <UIKit/NSString-UIStringDrawingDeprecated.h> | |
58 | ||
2435118f JF |
59 | #import <UIKit/UIImage-UIImageDeprecated.h> |
60 | ||
62b2dbad | 61 | #import <UIKit/UIView-Geometry.h> |
d5168fd6 | 62 | #import <UIKit/UIView-Hierarchy.h> |
62b2dbad | 63 | #import <UIKit/UIView-Rendering.h> |
d5168fd6 JF |
64 | |
65 | #import <SpringBoard/SBApplication.h> | |
394d1eb5 | 66 | #import <SpringBoard/SBApplicationIcon.h> |
d5168fd6 | 67 | #import <SpringBoard/SBAppWindow.h> |
502d350e | 68 | #import <SpringBoard/SBBookmarkIcon.h> |
62b2dbad | 69 | #import <SpringBoard/SBButtonBar.h> |
e6f0817b | 70 | #import <SpringBoard/SBCalendarIconContentsView.h> |
d5168fd6 | 71 | #import <SpringBoard/SBContentLayer.h> |
95a5777b | 72 | #import <SpringBoard/SBIconController.h> |
889cb4f2 | 73 | #import <SpringBoard/SBIconLabel.h> |
502d350e | 74 | #import <SpringBoard/SBSlidingAlertDisplay.h> |
08454e3a | 75 | #import <SpringBoard/SBStatusBarContentsView.h> |
d5fb6e01 | 76 | #import <SpringBoard/SBStatusBarController.h> |
08454e3a | 77 | #import <SpringBoard/SBStatusBarTimeView.h> |
d5168fd6 JF |
78 | #import <SpringBoard/SBUIController.h> |
79 | ||
d5fb6e01 JF |
80 | #import <MediaPlayer/MPVideoView.h> |
81 | #import <MediaPlayer/MPVideoView-PlaybackControl.h> | |
82 | ||
d5168fd6 JF |
83 | #import <CoreGraphics/CGGeometry.h> |
84 | ||
95a5777b JF |
85 | extern "C" void __clear_cache (char *beg, char *end); |
86 | ||
87 | Class $MPVideoView; | |
88 | ||
89 | Class $UIColor; | |
90 | Class $UIImage; | |
91 | Class $UIImageView; | |
92 | Class $UIWebDocumentView; | |
93 | ||
26c43b47 JF |
94 | @interface NSDictionary (WinterBoard) |
95 | - (UIColor *) colorForKey:(NSString *)key; | |
889cb4f2 | 96 | - (BOOL) boolForKey:(NSString *)key; |
26c43b47 JF |
97 | @end |
98 | ||
99 | @implementation NSDictionary (WinterBoard) | |
100 | ||
101 | - (UIColor *) colorForKey:(NSString *)key { | |
102 | NSString *value = [self objectForKey:key]; | |
103 | if (value == nil) | |
104 | return nil; | |
105 | /* XXX: incorrect */ | |
106 | return nil; | |
107 | } | |
108 | ||
889cb4f2 JF |
109 | - (BOOL) boolForKey:(NSString *)key { |
110 | if (NSString *value = [self objectForKey:key]) | |
111 | return [value boolValue]; | |
95a5777b | 112 | return false; |
889cb4f2 JF |
113 | } |
114 | ||
26c43b47 JF |
115 | @end |
116 | ||
f22a8989 | 117 | bool Debug_ = false; |
e6f0817b | 118 | bool Engineer_ = false; |
889cb4f2 | 119 | |
d5168fd6 | 120 | /* WinterBoard Backend {{{ */ |
d5168fd6 JF |
121 | void WBInject(const char *classname, const char *oldname, IMP newimp, const char *type) { |
122 | Class _class = objc_getClass(classname); | |
123 | if (_class == nil) | |
124 | return; | |
125 | if (!class_addMethod(_class, sel_registerName(oldname), newimp, type)) | |
2435118f | 126 | NSLog(@"WB:Error: failed to inject [%s %s]", classname, oldname); |
d5168fd6 JF |
127 | } |
128 | ||
d5168fd6 JF |
129 | /* }}} */ |
130 | ||
131 | @protocol WinterBoard | |
4e0efa01 JF |
132 | - (void) wb_cacheImageForIcon:(SBIcon *)icon; |
133 | - (UIImage *) wb_getCachedImagedForIcon:(SBIcon *)icon; | |
7ff778ee JF |
134 | - (CGSize) wb_renderedSizeOfNode:(id)node constrainedToWidth:(float)width; |
135 | - (void *) _node; | |
502d350e JF |
136 | - (void) wb_updateDesktopImage:(UIImage *)image; |
137 | - (UIImage *) wb_defaultDesktopImage; | |
138 | - (NSString *) wb_bundlePath; | |
d5168fd6 JF |
139 | - (NSString *) wb_pathForIcon; |
140 | - (NSString *) wb_pathForResource:(NSString *)resource ofType:(NSString *)type; | |
08454e3a JF |
141 | - (id) wb_init; |
142 | - (id) wb_layer; | |
d5168fd6 | 143 | - (id) wb_initWithSize:(CGSize)size; |
889cb4f2 | 144 | - (id) wb_initWithSize:(CGSize)size label:(NSString *)label; |
62b2dbad | 145 | - (id) wb_initWithFrame:(CGRect)frame; |
26c43b47 | 146 | - (id) wb_initWithCoder:(NSCoder *)coder; |
62b2dbad | 147 | - (void) wb_setFrame:(CGRect)frame; |
ca13798d | 148 | - (void) wb_drawRect:(CGRect)rect; |
d5168fd6 | 149 | - (void) wb_setBackgroundColor:(id)color; |
62b2dbad | 150 | - (void) wb_setAlpha:(float)value; |
26c43b47 JF |
151 | - (void) wb_setBarStyle:(int)style; |
152 | - (id) wb_initWithFrame:(CGRect)frame withBarStyle:(int)style withTintColor:(UIColor *)color; | |
08454e3a | 153 | - (void) wb_setOpaque:(BOOL)opaque; |
889cb4f2 | 154 | - (void) wb_setInDock:(BOOL)docked; |
08454e3a | 155 | - (void) wb_didMoveToSuperview; |
889cb4f2 | 156 | + (UIImage *) wb_imageNamed:(NSString *)name inBundle:(NSBundle *)bundle; |
d5fb6e01 | 157 | + (UIImage *) wb_applicationImageNamed:(NSString *)name; |
394d1eb5 JF |
158 | - (NSDictionary *) wb_infoDictionary; |
159 | - (UIImage *) wb_icon; | |
95a5777b | 160 | - (void) wb_appendIconList:(SBIconList *)list; |
d5fb6e01 JF |
161 | - (id) wb_initWithStatusBar:(id)bar mode:(int)mode; |
162 | - (id) wb_initWithMode:(int)mode orientation:(int)orientation; | |
502d350e JF |
163 | - (id) wb_imageAtPath:(NSString *)path; |
164 | - (id) wb_initWithContentsOfFile:(NSString *)file; | |
165 | - (id) wb_initWithContentsOfFile:(NSString *)file cache:(BOOL)cache; | |
d5fb6e01 | 166 | - (void) wb_setStatusBarMode:(int)mode orientation:(int)orientation duration:(float)duration fenceID:(int)id animation:(int)animation; |
d5168fd6 JF |
167 | @end |
168 | ||
502d350e JF |
169 | static NSMutableDictionary **__mappedImages; |
170 | static NSMutableDictionary *UIImages_; | |
171 | static NSMutableDictionary *PathImages_; | |
2435118f | 172 | |
502d350e JF |
173 | static NSFileManager *Manager_; |
174 | static NSDictionary *English_; | |
175 | static NSMutableDictionary *Info_; | |
176 | static NSMutableArray *themes_; | |
d5168fd6 | 177 | |
502d350e JF |
178 | static NSString *$getTheme$(NSArray *files) { |
179 | for (NSString *theme in themes_) | |
180 | for (NSString *file in files) { | |
181 | NSString *path([NSString stringWithFormat:@"%@/%@", theme, file]); | |
182 | if ([Manager_ fileExistsAtPath:path]) | |
183 | return path; | |
184 | } | |
185 | ||
186 | return nil; | |
187 | } | |
188 | ||
189 | static NSString *$pathForIcon$(SBApplication<WinterBoard> *self) { | |
d5fb6e01 JF |
190 | for (NSString *theme in themes_) { |
191 | NSString *identifier = [self bundleIdentifier]; | |
192 | NSString *folder = [[self path] lastPathComponent]; | |
193 | NSString *dname = [self displayName]; | |
194 | NSString *didentifier = [self displayIdentifier]; | |
195 | ||
95a5777b | 196 | if (Debug_) |
d5fb6e01 | 197 | NSLog(@"WB:Debug: [SBApplication(%@:%@:%@:%@) pathForIcon]", identifier, folder, dname, didentifier); |
62b2dbad | 198 | |
d5fb6e01 JF |
199 | #define testForIcon(Name) \ |
200 | if (NSString *name = Name) { \ | |
201 | NSString *path = [NSString stringWithFormat:@"%@/Icons/%@.png", theme, name]; \ | |
202 | if ([Manager_ fileExistsAtPath:path]) \ | |
203 | return path; \ | |
204 | } | |
205 | ||
206 | if (identifier != nil) { | |
207 | NSString *path = [NSString stringWithFormat:@"%@/Bundles/%@/icon.png", theme, identifier]; | |
208 | if ([Manager_ fileExistsAtPath:path]) | |
209 | return path; | |
26c43b47 | 210 | } |
889cb4f2 | 211 | |
d5fb6e01 JF |
212 | if (folder != nil) { |
213 | NSString *path = [NSString stringWithFormat:@"%@/Folders/%@/icon.png", theme, folder]; | |
214 | if ([Manager_ fileExistsAtPath:path]) | |
215 | return path; | |
216 | } | |
ca13798d | 217 | |
d5fb6e01 JF |
218 | testForIcon(identifier); |
219 | testForIcon(dname); | |
889cb4f2 | 220 | |
d5fb6e01 JF |
221 | if (didentifier != nil) { |
222 | testForIcon([English_ objectForKey:didentifier]); | |
889cb4f2 | 223 | |
d5fb6e01 JF |
224 | NSArray *parts = [didentifier componentsSeparatedByString:@"-"]; |
225 | if ([parts count] != 1) | |
226 | if (NSDictionary *english = [[[NSDictionary alloc] initWithContentsOfFile:[[self path] stringByAppendingString:@"/English.lproj/UIRoleDisplayNames.strings"]] autorelease]) | |
227 | testForIcon([english objectForKey:[parts lastObject]]); | |
228 | } | |
229 | } | |
889cb4f2 | 230 | |
394d1eb5 JF |
231 | return nil; |
232 | } | |
233 | ||
4e0efa01 JF |
234 | static NSMutableDictionary *Cache_; |
235 | ||
236 | static void SBIconModel$cacheImageForIcon$(SBIconModel<WinterBoard> *self, SEL sel, SBIcon *icon) { | |
237 | [self wb_cacheImageForIcon:icon]; | |
238 | NSString *key([icon displayIdentifier]); | |
239 | if (UIImage *value = [icon icon]) | |
240 | [Cache_ setObject:value forKey:key]; | |
241 | } | |
242 | ||
243 | static UIImage *SBIconModel$getCachedImagedForIcon$(SBIconModel<WinterBoard> *self, SEL sel, SBIcon *icon) { | |
244 | NSString *key([icon displayIdentifier]); | |
245 | if (UIImage *image = [Cache_ objectForKey:key]) | |
246 | return image; | |
247 | else | |
248 | return [self wb_getCachedImagedForIcon:icon]; | |
249 | } | |
250 | ||
394d1eb5 | 251 | static UIImage *SBApplicationIcon$icon(SBApplicationIcon<WinterBoard> *self, SEL sel) { |
d5fb6e01 | 252 | if (![Info_ boolForKey:@"ComposeStoreIcons"]) |
56539693 | 253 | if (NSString *path = $pathForIcon$([self application])) |
95a5777b | 254 | return [$UIImage imageWithContentsOfFile:path]; |
394d1eb5 JF |
255 | return [self wb_icon]; |
256 | } | |
257 | ||
502d350e JF |
258 | static UIImage *SBBookmarkIcon$icon(SBBookmarkIcon<WinterBoard> *self, SEL sel) { |
259 | if (Debug_) | |
260 | NSLog(@"WB:Debug:Bookmark(%@:%@)", [self displayIdentifier], [self displayName]); | |
261 | if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Icons/%@.png", [self displayName]]])) | |
262 | return [$UIImage imageWithContentsOfFile:path]; | |
263 | return [self wb_icon]; | |
264 | } | |
265 | ||
394d1eb5 | 266 | static NSString *SBApplication$pathForIcon(SBApplication<WinterBoard> *self, SEL sel) { |
d5fb6e01 JF |
267 | if (NSString *path = $pathForIcon$(self)) |
268 | return path; | |
d5168fd6 JF |
269 | return [self wb_pathForIcon]; |
270 | } | |
271 | ||
502d350e | 272 | static NSString *$pathForFile$inBundle$(NSString *file, NSBundle<WinterBoard> *bundle, bool ui) { |
d5fb6e01 | 273 | for (NSString *theme in themes_) { |
ca13798d JF |
274 | NSString *identifier = [bundle bundleIdentifier]; |
275 | ||
276 | if (identifier != nil) { | |
d5fb6e01 | 277 | NSString *path = [NSString stringWithFormat:@"%@/Bundles/%@/%@", theme, identifier, file]; |
ca13798d JF |
278 | if ([Manager_ fileExistsAtPath:path]) |
279 | return path; | |
280 | } | |
281 | ||
502d350e | 282 | if (NSString *folder = [[bundle wb_bundlePath] lastPathComponent]) { |
d5fb6e01 | 283 | NSString *path = [NSString stringWithFormat:@"%@/Folders/%@/%@", theme, folder, file]; |
ca13798d JF |
284 | if ([Manager_ fileExistsAtPath:path]) |
285 | return path; | |
286 | } | |
26c43b47 | 287 | |
889cb4f2 JF |
288 | #define remapResourceName(oldname, newname) \ |
289 | else if ([file isEqualToString:oldname]) { \ | |
d5fb6e01 | 290 | NSString *path = [NSString stringWithFormat:@"%@/%@.png", theme, newname]; \ |
889cb4f2 JF |
291 | if ([Manager_ fileExistsAtPath:path]) \ |
292 | return path; \ | |
293 | } | |
26c43b47 | 294 | |
ca13798d | 295 | if (identifier == nil || ![identifier isEqualToString:@"com.apple.springboard"]); |
8e65ed9f JF |
296 | remapResourceName(@"FSO_BG.png", @"StatusBar") |
297 | remapResourceName(@"SBDockBG.png", @"Dock") | |
298 | remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather") | |
95a5777b JF |
299 | |
300 | if (ui) { | |
301 | NSString *path = [NSString stringWithFormat:@"%@/UIImages/%@", theme, file]; | |
302 | if ([Manager_ fileExistsAtPath:path]) | |
303 | return path; | |
304 | } | |
d5168fd6 JF |
305 | } |
306 | ||
889cb4f2 JF |
307 | return nil; |
308 | } | |
309 | ||
95a5777b JF |
310 | static UIImage *CachedImageAtPath(NSString *path) { |
311 | UIImage *image = [PathImages_ objectForKey:path]; | |
312 | if (image != nil) | |
313 | return reinterpret_cast<id>(image) == [NSNull null] ? nil : image; | |
502d350e | 314 | image = [[$UIImage alloc] wb_initWithContentsOfFile:path cache:true]; |
95a5777b JF |
315 | if (image != nil) |
316 | image = [image autorelease]; | |
317 | [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:path]; | |
318 | return image; | |
319 | } | |
320 | ||
394d1eb5 | 321 | static UIImage *UIImage$imageNamed$inBundle$(Class<WinterBoard> self, SEL sel, NSString *name, NSBundle *bundle) { |
e6f0817b | 322 | NSString *key = [NSString stringWithFormat:@"B:%@/%@", [bundle bundleIdentifier], name]; |
95a5777b JF |
323 | UIImage *image = [PathImages_ objectForKey:key]; |
324 | if (image != nil) | |
325 | return reinterpret_cast<id>(image) == [NSNull null] ? nil : image; | |
889cb4f2 JF |
326 | if (Debug_) |
327 | NSLog(@"WB:Debug: [UIImage(%@) imageNamed:\"%@\"]", [bundle bundleIdentifier], name); | |
95a5777b JF |
328 | if (NSString *path = $pathForFile$inBundle$(name, bundle, false)) |
329 | image = CachedImageAtPath(path); | |
330 | if (image == nil) | |
331 | image = [self wb_imageNamed:name inBundle:bundle]; | |
332 | [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key]; | |
333 | return image; | |
889cb4f2 JF |
334 | } |
335 | ||
394d1eb5 | 336 | static UIImage *UIImage$imageNamed$(Class<WinterBoard> self, SEL sel, NSString *name) { |
889cb4f2 JF |
337 | return UIImage$imageNamed$inBundle$(self, sel, name, [NSBundle mainBundle]); |
338 | } | |
339 | ||
d5fb6e01 JF |
340 | static UIImage *UIImage$applicationImageNamed$(Class<WinterBoard> self, SEL sel, NSString *name) { |
341 | NSBundle *bundle = [NSBundle mainBundle]; | |
342 | if (Debug_) | |
343 | NSLog(@"WB:Debug: [UIImage(%@) applicationImageNamed:\"%@\"]", [bundle bundleIdentifier], name); | |
95a5777b JF |
344 | if (NSString *path = $pathForFile$inBundle$(name, bundle, false)) |
345 | return CachedImageAtPath(path); | |
d5fb6e01 JF |
346 | return [self wb_applicationImageNamed:name]; |
347 | } | |
348 | ||
502d350e JF |
349 | @interface NSString (WinterBoard) |
350 | - (NSString *) wb_themedPath; | |
351 | @end | |
352 | ||
353 | @implementation NSString (WinterBoard) | |
354 | ||
355 | - (NSString *) wb_themedPath { | |
e6f0817b JF |
356 | if (Debug_) |
357 | NSLog(@"WB:Debug:Bypass(\"%@\")", self); | |
502d350e JF |
358 | return self; |
359 | } | |
360 | ||
361 | @end | |
362 | ||
363 | static NSMutableDictionary *Files_; | |
364 | ||
365 | #define WBDelegate(delegate) \ | |
366 | - (NSMethodSignature*) methodSignatureForSelector:(SEL)sel { \ | |
367 | if (Engineer_) \ | |
368 | NSLog(@"WB:MS:%s:(%s)", class_getName([self class]), sel_getName(sel)); \ | |
369 | if (NSMethodSignature *sig = [delegate methodSignatureForSelector:sel]) \ | |
370 | return sig; \ | |
371 | NSLog(@"WB:Error: [%s methodSignatureForSelector:(%s)]", class_getName([self class]), sel_getName(sel)); \ | |
372 | return nil; \ | |
373 | } \ | |
374 | \ | |
375 | - (void) forwardInvocation:(NSInvocation*)inv { \ | |
376 | SEL sel = [inv selector]; \ | |
377 | if ([delegate respondsToSelector:sel]) \ | |
378 | [inv invokeWithTarget:delegate]; \ | |
379 | else \ | |
380 | NSLog(@"WB:Error: [%s forwardInvocation:(%s)]", class_getName([self class]), sel_getName(sel)); \ | |
381 | } | |
382 | ||
383 | /*@interface WBBundlePath : NSProxy { | |
384 | NSBundle<WinterBoard> *bundle_; | |
385 | NSString *path_; | |
386 | } | |
387 | ||
388 | - (id) initWithBundle:(NSBundle *)bundle path:(NSString *)path; | |
389 | ||
390 | - (NSString *) wb_themedPath; | |
391 | ||
392 | @end | |
393 | ||
394 | @implementation WBBundlePath | |
395 | ||
396 | - (void) dealloc { | |
397 | [bundle_ release]; | |
398 | [path_ release]; | |
399 | [super dealloc]; | |
400 | } | |
401 | ||
402 | - (id) initWithBundle:(NSBundle *)bundle path:(NSString *)path { | |
403 | bundle_ = [bundle retain]; | |
404 | path_ = [path retain]; | |
405 | return self; | |
406 | } | |
407 | ||
408 | WBDelegate(path_) | |
409 | ||
410 | - (NSString *) stringByAppendingPathComponent:(NSString *)component { | |
411 | NSLog(@"WB:Debug:app:%@:%@", path_, component); | |
412 | return [[[WBBundlePath alloc] initWithBundle:bundle_ path:[path_ stringByAppendingPathComponent:component]] autorelease]; | |
413 | } | |
414 | ||
415 | - (NSString *) stringByAppendingPathExtension:(NSString *)extension { | |
416 | return [[[WBBundlePath alloc] initWithBundle:bundle_ path:[path_ stringByAppendingPathExtension:extension]] autorelease]; | |
417 | } | |
418 | ||
419 | - (const char *) UTF8String { | |
420 | const char *string = [path_ UTF8String]; | |
421 | NSLog(@"WB:Debug:UTF=%s", string); | |
422 | return string; | |
423 | } | |
424 | ||
425 | - (NSString *) description { | |
426 | return [path_ description]; | |
427 | } | |
428 | ||
429 | - (NSString *) wb_themedPath { | |
430 | return path_; | |
431 | NSString *path = [Files_ objectForKey:path_]; | |
432 | if (path == nil) { | |
433 | NSString *path = [bundle_ wb_bundlePath]; | |
434 | if (![path_ hasPrefix:path]) { | |
435 | NSLog(@"WB:Error:![@\"%@\" hasPrefix:@\"%@\"]", path_, path); | |
436 | return path_; | |
437 | } | |
438 | path = [path_ substringFromIndex:([path length] + 1)]; | |
439 | path = $pathForFile$inBundle$(path, bundle_, false); | |
440 | if (path == nil) | |
441 | path = reinterpret_cast<NSString *>([NSNull null]); | |
442 | [Files_ setObject:path forKey:path_]; | |
443 | if (Debug_) | |
444 | NSLog(@"WB:Debug:ThemePath(\"%@\")->\"%@\"", path_, path); | |
445 | } | |
446 | if (reinterpret_cast<id>(path) == [NSNull null]) | |
447 | path = path_; | |
448 | NSLog(@"WB:Debug:ThemePath=%@", path); | |
449 | return path; | |
450 | } | |
451 | ||
452 | @end*/ | |
453 | ||
454 | static NSString *NSBundle$bundlePath$(NSBundle<WinterBoard> *self, SEL sel) { | |
455 | //return [[WBBundlePath alloc] initWithBundle:self path:[self wb_bundlePath]]; | |
456 | return [self wb_bundlePath]; | |
457 | } | |
458 | ||
394d1eb5 | 459 | static NSString *NSBundle$pathForResource$ofType$(NSBundle<WinterBoard> *self, SEL sel, NSString *resource, NSString *type) { |
889cb4f2 JF |
460 | NSString *file = type == nil ? resource : [NSString stringWithFormat:@"%@.%@", resource, type]; |
461 | if (Debug_) | |
462 | NSLog(@"WB:Debug: [NSBundle(%@) pathForResource:\"%@\"]", [self bundleIdentifier], file); | |
95a5777b | 463 | if (NSString *path = $pathForFile$inBundle$(file, self, false)) |
ca13798d | 464 | return path; |
d5168fd6 JF |
465 | return [self wb_pathForResource:resource ofType:type]; |
466 | } | |
467 | ||
502d350e | 468 | static bool $setBarStyle$_(NSString *name, UIView<WinterBoard> *self, int style) { |
95a5777b JF |
469 | if (Debug_) |
470 | NSLog(@"WB:Debug:%@Style:%d", name, style); | |
471 | NSNumber *number = nil; | |
472 | if (number == nil) | |
473 | number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style-%d", name, style]]; | |
474 | if (number == nil) | |
475 | number = [Info_ objectForKey:[NSString stringWithFormat:@"%@Style", name]]; | |
476 | if (number == nil) | |
477 | return false; | |
478 | else { | |
479 | style = [number intValue]; | |
480 | if (Debug_) | |
481 | NSLog(@"WB:Debug:%@Style=%d", name, style); | |
482 | [self wb_setBarStyle:style]; | |
d5fb6e01 | 483 | return true; |
26c43b47 | 484 | } |
26c43b47 JF |
485 | } |
486 | ||
e6f0817b JF |
487 | static void SBCalendarIconContentsView$drawRect$(SBCalendarIconContentsView<WinterBoard> *self, SEL sel, CGRect rect) { |
488 | CFLocaleRef locale(CFLocaleCopyCurrent()); | |
489 | CFDateFormatterRef formatter(CFDateFormatterCreate(NULL, locale, kCFDateFormatterNoStyle, kCFDateFormatterNoStyle)); | |
490 | CFRelease(locale); | |
491 | ||
492 | CFDateRef now(CFDateCreate(NULL, CFAbsoluteTimeGetCurrent())); | |
493 | ||
494 | CFDateFormatterSetFormat(formatter, CFSTR("d")); | |
495 | CFStringRef date(CFDateFormatterCreateStringWithDate(NULL, formatter, now)); | |
496 | CFDateFormatterSetFormat(formatter, CFSTR("EEEE")); | |
497 | CFStringRef day(CFDateFormatterCreateStringWithDate(NULL, formatter, now)); | |
498 | ||
499 | CFRelease(now); | |
500 | ||
501 | CFRelease(formatter); | |
502 | ||
503 | NSString *datestyle(@"" | |
504 | "font-family: Helvetica; " | |
505 | "font-weight: bold; " | |
506 | "font-size: 39px; " | |
507 | "color: #333333; " | |
508 | "alpha: 1.0; " | |
509 | ""); | |
510 | ||
511 | NSString *daystyle(@"" | |
512 | "font-family: Helvetica; " | |
513 | "font-weight: bold; " | |
514 | "font-size: 9px; " | |
515 | "color: white; " | |
516 | "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px; " | |
517 | ""); | |
518 | ||
519 | if (NSString *style = [Info_ objectForKey:@"CalendarIconDateStyle"]) | |
520 | datestyle = [datestyle stringByAppendingString:style]; | |
521 | if (NSString *style = [Info_ objectForKey:@"CalendarIconDayStyle"]) | |
522 | daystyle = [daystyle stringByAppendingString:style]; | |
523 | ||
cf31d246 | 524 | float width([self bounds].size.width); |
e6f0817b JF |
525 | CGSize datesize = [(NSString *)date sizeWithStyle:datestyle forWidth:width]; |
526 | CGSize daysize = [(NSString *)day sizeWithStyle:daystyle forWidth:width]; | |
527 | ||
528 | [(NSString *)date drawAtPoint:CGPointMake( | |
9b800fcd | 529 | (width - datesize.width) / 2, (71 - datesize.height) / 2 |
e6f0817b JF |
530 | ) withStyle:datestyle]; |
531 | ||
532 | [(NSString *)day drawAtPoint:CGPointMake( | |
533 | (width - daysize.width) / 2, (16 - daysize.height) / 2 | |
534 | ) withStyle:daystyle]; | |
535 | ||
536 | CFRelease(date); | |
537 | CFRelease(day); | |
538 | } | |
539 | ||
502d350e | 540 | /*static id UINavigationBarBackground$initWithFrame$withBarStyle$withTintColor$(UINavigationBarBackground<WinterBoard> *self, SEL sel, CGRect frame, int style, UIColor *tint) { |
26c43b47 JF |
541 | _trace(); |
542 | ||
d5fb6e01 JF |
543 | if (NSNumber *number = [Info_ objectForKey:@"NavigationBarStyle"]) |
544 | style = [number intValue]; | |
26c43b47 | 545 | |
d5fb6e01 JF |
546 | if (UIColor *color = [Info_ colorForKey:@"NavigationBarTint"]) |
547 | tint = color; | |
26c43b47 JF |
548 | |
549 | return [self wb_initWithFrame:frame withBarStyle:style withTintColor:tint]; | |
550 | }*/ | |
551 | ||
502d350e | 552 | /*static id UINavigationBar$initWithCoder$(SBAppWindow<WinterBoard> *self, SEL sel, CGRect frame, NSCoder *coder) { |
26c43b47 JF |
553 | self = [self wb_initWithCoder:coder]; |
554 | if (self == nil) | |
555 | return nil; | |
556 | UINavigationBar$setBarStyle$_(self); | |
557 | return self; | |
558 | } | |
559 | ||
502d350e | 560 | static id UINavigationBar$initWithFrame$(SBAppWindow<WinterBoard> *self, SEL sel, CGRect frame) { |
26c43b47 JF |
561 | self = [self wb_initWithFrame:frame]; |
562 | if (self == nil) | |
563 | return nil; | |
564 | UINavigationBar$setBarStyle$_(self); | |
565 | return self; | |
566 | }*/ | |
567 | ||
95a5777b JF |
568 | static void UIToolbar$setBarStyle$(UIToolbar<WinterBoard> *self, SEL sel, int style) { |
569 | if ($setBarStyle$_(@"Toolbar", self, style)) | |
570 | return; | |
571 | return [self wb_setBarStyle:style]; | |
572 | } | |
573 | ||
574 | static void UINavigationBar$setBarStyle$(UINavigationBar<WinterBoard> *self, SEL sel, int style) { | |
575 | if ($setBarStyle$_(@"NavigationBar", self, style)) | |
26c43b47 JF |
576 | return; |
577 | return [self wb_setBarStyle:style]; | |
578 | } | |
579 | ||
394d1eb5 | 580 | static void $didMoveToSuperview(SBButtonBar<WinterBoard> *self, SEL sel) { |
95a5777b | 581 | [[self superview] setBackgroundColor:[$UIColor clearColor]]; |
08454e3a JF |
582 | [self wb_didMoveToSuperview]; |
583 | } | |
62b2dbad | 584 | |
502d350e JF |
585 | static id UIImage$imageAtPath$(NSObject<WinterBoard> *self, SEL sel, NSString *path) { |
586 | return [self wb_imageAtPath:[path wb_themedPath]]; | |
587 | } | |
d5fb6e01 | 588 | |
502d350e JF |
589 | static id $initWithContentsOfFile$(NSObject<WinterBoard> *self, SEL sel, NSString *file) { |
590 | return [self wb_initWithContentsOfFile:[file wb_themedPath]]; | |
394d1eb5 JF |
591 | } |
592 | ||
502d350e JF |
593 | static id UIImage$initWithContentsOfFile$cache$(UIImage<WinterBoard> *self, SEL sel, NSString *file, BOOL cache) { |
594 | return [self wb_initWithContentsOfFile:[file wb_themedPath] cache:cache]; | |
595 | } | |
596 | ||
597 | static UIImage *UIImage$defaultDesktopImage$(UIImage<WinterBoard> *self, SEL sel) { | |
598 | if (Debug_) | |
599 | NSLog(@"WB:Debug:DefaultDesktopImage"); | |
600 | if (NSString *path = $getTheme$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])) | |
601 | return [$UIImage imageWithContentsOfFile:path]; | |
602 | return [self wb_defaultDesktopImage]; | |
603 | } | |
604 | ||
605 | static UIImageView *WallpaperImage_; | |
606 | static UIWebDocumentView *WallpaperPage_; | |
607 | static NSURL *WallpaperURL_; | |
95a5777b | 608 | |
394d1eb5 | 609 | static id SBContentLayer$initWithSize$(SBContentLayer<WinterBoard> *self, SEL sel, CGSize size) { |
d5168fd6 JF |
610 | self = [self wb_initWithSize:size]; |
611 | if (self == nil) | |
612 | return nil; | |
613 | ||
d5fb6e01 | 614 | if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"])) { |
95a5777b | 615 | MPVideoView *video = [[[$MPVideoView alloc] initWithFrame:[self bounds]] autorelease]; |
d5fb6e01 JF |
616 | [video setMovieWithPath:path]; |
617 | [video setRepeatMode:1]; | |
618 | [video setRepeatGap:0]; | |
619 | [self addSubview:video]; | |
620 | [video playFromBeginning];; | |
621 | } | |
622 | ||
95a5777b JF |
623 | UIImage *image; |
624 | if (NSString *path = $getTheme$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil])) { | |
502d350e | 625 | image = [[$UIImage alloc] wb_initWithContentsOfFile:path]; |
95a5777b JF |
626 | if (image != nil) |
627 | image = [image autorelease]; | |
628 | } else image = nil; | |
629 | ||
502d350e JF |
630 | if (WallpaperImage_ != nil) |
631 | [WallpaperImage_ release]; | |
632 | WallpaperImage_ = [[$UIImageView alloc] initWithImage:image]; | |
633 | [self addSubview:WallpaperImage_]; | |
d5fb6e01 JF |
634 | |
635 | if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"])) { | |
394d1eb5 JF |
636 | CGRect bounds = [self bounds]; |
637 | ||
95a5777b JF |
638 | UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]); |
639 | [view setAutoresizes:true]; | |
394d1eb5 | 640 | |
502d350e JF |
641 | if (WallpaperPage_ != nil) |
642 | [WallpaperPage_ release]; | |
643 | WallpaperPage_ = [view retain]; | |
644 | ||
645 | if (WallpaperURL_ != nil) | |
646 | [WallpaperURL_ release]; | |
647 | WallpaperURL_ = [[NSURL fileURLWithPath:path] retain]; | |
648 | ||
649 | [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]]; | |
394d1eb5 | 650 | |
95a5777b JF |
651 | [[view webView] setDrawsBackground:false]; |
652 | [view setBackgroundColor:[$UIColor clearColor]]; | |
394d1eb5 JF |
653 | |
654 | [self addSubview:view]; | |
08454e3a | 655 | } |
d5168fd6 JF |
656 | |
657 | return self; | |
658 | } | |
659 | ||
502d350e JF |
660 | static void SBSlidingAlertDisplay$updateDesktopImage$(SBSlidingAlertDisplay<WinterBoard> *self, SEL sel, UIImage *image) { |
661 | NSString *path = $getTheme$([NSArray arrayWithObject:@"LockBackground.html"]); | |
662 | ||
663 | if (path) { | |
664 | UIView *background; | |
665 | object_getInstanceVariable(self, "_backgroundView", reinterpret_cast<void **>(&background)); | |
666 | if (background != nil) | |
667 | path = nil; | |
668 | } | |
669 | ||
670 | [self wb_updateDesktopImage:image]; | |
671 | ||
672 | if (path != nil) { | |
673 | CGRect bounds = [self bounds]; | |
674 | ||
675 | UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]); | |
676 | [view setAutoresizes:true]; | |
677 | ||
678 | if (WallpaperPage_ != nil) | |
679 | [WallpaperPage_ release]; | |
680 | WallpaperPage_ = [view retain]; | |
681 | ||
682 | if (WallpaperURL_ != nil) | |
683 | [WallpaperURL_ release]; | |
684 | WallpaperURL_ = [[NSURL fileURLWithPath:path] retain]; | |
685 | ||
686 | [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]]; | |
687 | ||
688 | [[view webView] setDrawsBackground:false]; | |
689 | [view setBackgroundColor:[$UIColor clearColor]]; | |
690 | ||
691 | UIView *background; | |
692 | object_getInstanceVariable(self, "_backgroundView", reinterpret_cast<void **>(&background)); | |
693 | NSLog(@"back:%@", background); | |
694 | ||
695 | [self insertSubview:view aboveSubview:background]; | |
ca13798d | 696 | } |
502d350e | 697 | } |
ca13798d | 698 | |
95a5777b JF |
699 | static unsigned *__currentContextCount; |
700 | static void ***__currentContextStack; | |
ca13798d | 701 | |
95a5777b | 702 | /*extern "C" CGColorRef CGGStateGetSystemColor(void *); |
ca13798d JF |
703 | extern "C" CGColorRef CGGStateGetFillColor(void *); |
704 | extern "C" CGColorRef CGGStateGetStrokeColor(void *); | |
95a5777b | 705 | extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/ |
ca13798d JF |
706 | |
707 | @interface WBTime : NSProxy { | |
708 | NSString *time_; | |
709 | _transient SBStatusBarTimeView *view_; | |
889cb4f2 JF |
710 | } |
711 | ||
ca13798d | 712 | - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view; |
889cb4f2 JF |
713 | |
714 | @end | |
715 | ||
ca13798d | 716 | @implementation WBTime |
889cb4f2 JF |
717 | |
718 | - (void) dealloc { | |
ca13798d | 719 | [time_ release]; |
889cb4f2 JF |
720 | [super dealloc]; |
721 | } | |
722 | ||
ca13798d JF |
723 | - (id) initWithTime:(NSString *)time view:(SBStatusBarTimeView *)view { |
724 | time_ = [time retain]; | |
725 | view_ = view; | |
889cb4f2 JF |
726 | return self; |
727 | } | |
728 | ||
ca13798d JF |
729 | WBDelegate(time_) |
730 | ||
731 | - (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode { | |
d5fb6e01 JF |
732 | if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) { |
733 | BOOL mode; | |
95a5777b | 734 | object_getInstanceVariable(view_, "_mode", reinterpret_cast<void **>(&mode)); |
d5fb6e01 JF |
735 | |
736 | [time_ drawAtPoint:point withStyle:[NSString stringWithFormat:@"" | |
737 | "font-family: Helvetica; " | |
738 | "font-weight: bold; " | |
739 | "font-size: 14px; " | |
740 | "color: %@; " | |
741 | "%@", mode ? @"white" : @"black", custom]]; | |
742 | ||
743 | return CGSizeZero; | |
744 | } | |
ca13798d JF |
745 | |
746 | return [time_ drawAtPoint:point forWidth:width withFont:font lineBreakMode:mode]; | |
889cb4f2 JF |
747 | } |
748 | ||
ca13798d JF |
749 | @end |
750 | ||
751 | @interface WBIconLabel : NSProxy { | |
752 | NSString *string_; | |
753 | BOOL docked_; | |
889cb4f2 JF |
754 | } |
755 | ||
ca13798d JF |
756 | - (id) initWithString:(NSString *)string; |
757 | ||
758 | @end | |
759 | ||
d5fb6e01 | 760 | static void SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$(SBStatusBarController<WinterBoard> *self, SEL sel, int mode, int orientation, float duration, int id, int animation) { |
95a5777b JF |
761 | if (Debug_) |
762 | NSLog(@"WB:Debug:setStatusBarMode:%d", mode); | |
502d350e | 763 | if (mode < 100) // 104:hidden 105:glowing |
95a5777b JF |
764 | if (NSNumber *number = [Info_ objectForKey:@"StatusBarMode"]) |
765 | mode = [number intValue]; | |
d5fb6e01 JF |
766 | return [self wb_setStatusBarMode:mode orientation:orientation duration:duration fenceID:id animation:animation]; |
767 | } | |
768 | ||
769 | /*static id SBStatusBar$initWithMode$orientation$(SBStatusBar<WinterBoard> *self, SEL sel, int mode, int orientation) { | |
770 | return [self wb_initWithMode:mode orientation:orientation]; | |
771 | }*/ | |
772 | ||
773 | static id SBStatusBarContentsView$initWithStatusBar$mode$(SBStatusBarContentsView<WinterBoard> *self, SEL sel, id bar, int mode) { | |
774 | if (NSNumber *number = [Info_ objectForKey:@"StatusBarContentsMode"]) | |
775 | mode = [number intValue]; | |
776 | return [self wb_initWithStatusBar:bar mode:mode]; | |
777 | } | |
778 | ||
394d1eb5 | 779 | static void SBStatusBarTimeView$drawRect$(SBStatusBarTimeView<WinterBoard> *self, SEL sel, CGRect rect) { |
ca13798d | 780 | id time; |
95a5777b | 781 | object_getInstanceVariable(self, "_time", reinterpret_cast<void **>(&time)); |
ca13798d | 782 | if (time != nil && [time class] != [WBTime class]) |
95a5777b | 783 | object_setInstanceVariable(self, "_time", reinterpret_cast<void *>([[WBTime alloc] initWithTime:[time autorelease] view:self])); |
ca13798d JF |
784 | return [self wb_drawRect:rect]; |
785 | } | |
786 | ||
95a5777b JF |
787 | static void SBIconController$appendIconList$(SBIconController<WinterBoard> *self, SEL sel, SBIconList *list) { |
788 | if (Debug_) | |
789 | NSLog(@"appendIconList:%@", list); | |
790 | return [self wb_appendIconList:list]; | |
791 | } | |
792 | ||
cf31d246 JF |
793 | static id SBIconLabel$initWithSize$label$(SBIconLabel<WinterBoard> *self, SEL sel, CGSize size, NSString *label) { |
794 | self = [self wb_initWithSize:size label:label]; | |
795 | if (self != nil) | |
796 | [self setClipsToBounds:NO]; | |
797 | return self; | |
798 | } | |
799 | ||
394d1eb5 | 800 | static void SBIconLabel$setInDock$(SBIconLabel<WinterBoard> *self, SEL sel, BOOL docked) { |
889cb4f2 | 801 | id label; |
95a5777b | 802 | object_getInstanceVariable(self, "_label", reinterpret_cast<void **>(&label)); |
d5fb6e01 | 803 | if (![Info_ boolForKey:@"UndockedIconLabels"]) |
95a5777b | 804 | docked = true; |
889cb4f2 JF |
805 | if (label != nil && [label respondsToSelector:@selector(setInDock:)]) |
806 | [label setInDock:docked]; | |
807 | return [self wb_setInDock:docked]; | |
808 | } | |
809 | ||
7ff778ee JF |
810 | @class WebCoreFrameBridge; |
811 | static CGSize WebCoreFrameBridge$renderedSizeOfNode$constrainedToWidth$(WebCoreFrameBridge<WinterBoard> *self, SEL sel, id node, float width) { | |
812 | if (node == nil) | |
813 | return CGSizeZero; | |
814 | void **core(reinterpret_cast<void **>([node _node])); | |
815 | if (core == NULL || core[6] == NULL) | |
816 | return CGSizeZero; | |
817 | return [self wb_renderedSizeOfNode:node constrainedToWidth:width]; | |
818 | } | |
819 | ||
cf31d246 JF |
820 | static void SBIconLabel$drawRect$(SBIconLabel<WinterBoard> *self, SEL sel, CGRect rect) { |
821 | CGRect bounds = [self bounds]; | |
e6f0817b | 822 | |
a3fa54a5 JF |
823 | static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL); |
824 | ||
cf31d246 | 825 | BOOL docked; |
a3fa54a5 JF |
826 | Ivar ivar = object_getInstanceVariable(self, "_inDock", reinterpret_cast<void **>(&docked)); |
827 | docked = (docked & (ivar_getOffset(ivar) == ivar_getOffset(drawMoreLegibly) ? 0x2 : 0x1)) != 0; | |
cf31d246 JF |
828 | |
829 | NSString *label; | |
830 | object_getInstanceVariable(self, "_label", reinterpret_cast<void **>(&label)); | |
831 | ||
832 | NSString *style = [NSString stringWithFormat:@"" | |
833 | "font-family: Helvetica; " | |
834 | "font-weight: bold; " | |
835 | "font-size: 11px; " | |
836 | "color: %@; " | |
837 | "", docked ? @"white" : @"#b3b3b3"]; | |
838 | ||
839 | if (docked) | |
840 | style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "]; | |
841 | float max = 75, width = [label sizeWithStyle:style forWidth:320].width; | |
842 | if (width > max) | |
843 | style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", ((width - max) / ([label length] - 1))]]; | |
844 | if (NSString *custom = [Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")]) | |
845 | style = [style stringByAppendingString:custom]; | |
846 | ||
847 | CGSize size = [label sizeWithStyle:style forWidth:bounds.size.width]; | |
848 | [label drawAtPoint:CGPointMake((bounds.size.width - size.width) / 2, 0) withStyle:style]; | |
889cb4f2 JF |
849 | } |
850 | ||
2435118f JF |
851 | extern "C" void FindMappedImages(void); |
852 | extern "C" NSData *UIImagePNGRepresentation(UIImage *); | |
853 | ||
95a5777b JF |
854 | static UIImage *(*_UIImageAtPath)(NSString *name, NSBundle *path); |
855 | static CGImageRef *(*_UIImageRefAtPath)(NSString *path, bool cache, UIImageOrientation *orientation); | |
856 | static UIImage *(*_UIImageWithName)(NSString *name); | |
e6f0817b | 857 | static UIImage *(*_UIImageWithNameInDomain)(NSString *name, NSString *domain); |
95a5777b JF |
858 | static NSBundle *(*_UIKitBundle)(); |
859 | static void (*_UISharedImageInitialize)(bool); | |
860 | static int (*_UISharedImageNameGetIdentifier)(NSString *); | |
861 | static UIImage *(*_UISharedImageWithIdentifier)(int); | |
862 | ||
863 | static UIImage *$_UIImageWithName(NSString *name) { | |
864 | int id(_UISharedImageNameGetIdentifier(name)); | |
865 | if (Debug_) | |
866 | NSLog(@"WB:Debug: UIImageWithName(\"%@\", %d)", name, id); | |
867 | ||
868 | if (id == -1) | |
869 | return _UIImageAtPath(name, _UIKitBundle()); | |
870 | else { | |
871 | NSNumber *key([NSNumber numberWithInt:id]); | |
872 | UIImage *image = [UIImages_ objectForKey:key]; | |
873 | if (image != nil) | |
874 | return reinterpret_cast<id>(image) == [NSNull null] ? nil : image; | |
875 | if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true)) { | |
502d350e | 876 | image = [[$UIImage alloc] wb_initWithContentsOfFile:path]; |
95a5777b JF |
877 | if (image != nil) |
878 | [image autorelease]; | |
879 | } | |
880 | if (image == nil) | |
881 | image = _UISharedImageWithIdentifier(id); | |
882 | [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key]; | |
883 | return image; | |
884 | } | |
885 | } | |
886 | ||
e6f0817b JF |
887 | static UIImage *$_UIImageWithNameInDomain(NSString *name, NSString *domain) { |
888 | NSString *key = [NSString stringWithFormat:@"D:%zu%@%@", [domain length], domain, name]; | |
889 | UIImage *image = [PathImages_ objectForKey:key]; | |
890 | if (image != nil) | |
891 | return reinterpret_cast<id>(image) == [NSNull null] ? nil : image; | |
95a5777b | 892 | if (Debug_) |
e6f0817b JF |
893 | NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain); |
894 | if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]])) { | |
895 | image = [[$UIImage alloc] wb_initWithContentsOfFile:path]; | |
896 | if (image != nil) | |
897 | [image autorelease]; | |
95a5777b | 898 | } |
e6f0817b JF |
899 | if (image == nil) |
900 | image = _UIImageWithNameInDomain(name, domain); | |
901 | [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast<id>(image)) forKey:key]; | |
902 | return image; | |
95a5777b JF |
903 | } |
904 | ||
905 | template <typename Type_> | |
906 | static void WBReplace(Type_ *symbol, Type_ *replace) { | |
907 | return WBReplace(symbol, replace, static_cast<Type_ **>(NULL)); | |
908 | } | |
909 | ||
910 | #define AudioToolbox "/System/Library/Frameworks/AudioToolbox.framework/AudioToolbox" | |
911 | #define UIKit "/System/Library/Frameworks/UIKit.framework/UIKit" | |
912 | ||
913 | /*static void UIWebDocumentView$setViewportSize$forDocumentTypes$(UIWebDocumentView *self, SEL sel, CGSize size, int type) { | |
914 | NSLog(@"WB:Examine: %f:%f:%u", size.width, size.height, type); | |
915 | }*/ | |
916 | ||
917 | static bool (*_Z24GetFileNameForThisActionmPcRb)(unsigned long, char *, bool &); | |
918 | ||
919 | static bool $_Z24GetFileNameForThisActionmPcRb(unsigned long a0, char *a1, bool &a2) { | |
920 | bool value = _Z24GetFileNameForThisActionmPcRb(a0, a1, a2); | |
921 | if (Debug_) | |
922 | NSLog(@"WB:Debug:GetFileNameForThisAction(%u, %s, %u) = %u", a0, value ? a1 : NULL, a2, value); | |
923 | ||
924 | if (value) { | |
925 | NSString *path = [NSString stringWithUTF8String:a1]; | |
926 | if ([path hasPrefix:@"/System/Library/Audio/UISounds/"]) { | |
927 | NSString *file = [path substringFromIndex:31]; | |
928 | NSLog(@"%@", file); | |
929 | for (NSString *theme in themes_) { | |
930 | NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]); | |
931 | if ([Manager_ fileExistsAtPath:path]) { | |
932 | strcpy(a1, [path UTF8String]); | |
933 | continue; | |
934 | } | |
935 | } | |
936 | } | |
937 | } | |
938 | return value; | |
939 | } | |
940 | ||
941 | static void ChangeWallpaper( | |
942 | CFNotificationCenterRef center, | |
943 | void *observer, | |
944 | CFStringRef name, | |
945 | const void *object, | |
946 | CFDictionaryRef info | |
947 | ) { | |
948 | if (Debug_) | |
949 | NSLog(@"WB:Debug:ChangeWallpaper!"); | |
502d350e | 950 | |
95a5777b JF |
951 | UIImage *image; |
952 | if (NSString *path = $getTheme$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil])) { | |
502d350e | 953 | image = [[$UIImage alloc] wb_initWithContentsOfFile:path]; |
95a5777b JF |
954 | if (image != nil) |
955 | image = [image autorelease]; | |
956 | } else image = nil; | |
502d350e JF |
957 | |
958 | if (WallpaperImage_ != nil) | |
959 | [WallpaperImage_ setImage:image]; | |
960 | if (WallpaperPage_ != nil) | |
961 | [WallpaperPage_ loadRequest:[NSURLRequest requestWithURL:WallpaperURL_]]; | |
962 | ||
95a5777b | 963 | } |
394d1eb5 | 964 | |
e6f0817b JF |
965 | void WBRename(bool instance, const char *name, SEL sel, IMP imp) { |
966 | Class _class = objc_getClass(name); | |
967 | if (_class == nil) { | |
968 | if (Debug_) | |
969 | NSLog(@"WB:Warning: cannot find class [%s]", name); | |
970 | return; | |
971 | } | |
972 | if (!instance) | |
973 | _class = object_getClass(_class); | |
974 | MSHookMessage(_class, sel, imp, "wb_"); | |
975 | } | |
976 | ||
d5168fd6 | 977 | extern "C" void WBInitialize() { |
95a5777b JF |
978 | if (dlopen(UIKit, RTLD_LAZY | RTLD_NOLOAD) == NULL) |
979 | return; | |
2435118f | 980 | NSLog(@"WB:Notice: Installing WinterBoard..."); |
d5168fd6 JF |
981 | |
982 | NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; | |
983 | ||
95a5777b JF |
984 | NSBundle *MediaPlayer = [NSBundle bundleWithPath:@"/System/Library/Frameworks/MediaPlayer.framework"]; |
985 | if (MediaPlayer != nil) | |
986 | [MediaPlayer load]; | |
394d1eb5 | 987 | |
95a5777b | 988 | $MPVideoView = objc_getClass("MPVideoView"); |
394d1eb5 | 989 | |
95a5777b JF |
990 | $UIColor = objc_getClass("UIColor"); |
991 | $UIImage = objc_getClass("UIImage"); | |
992 | $UIImageView = objc_getClass("UIImageView"); | |
993 | $UIWebDocumentView = objc_getClass("UIWebDocumentView"); | |
994 | ||
e6f0817b | 995 | struct nlist nl[12]; |
95a5777b | 996 | memset(nl, 0, sizeof(nl)); |
394d1eb5 | 997 | |
95a5777b JF |
998 | nl[0].n_un.n_name = (char *) "___currentContextCount"; |
999 | nl[1].n_un.n_name = (char *) "___currentContextStack"; | |
1000 | nl[2].n_un.n_name = (char *) "___mappedImages"; | |
1001 | nl[3].n_un.n_name = (char *) "__UIImageAtPath"; | |
1002 | nl[4].n_un.n_name = (char *) "__UIImageRefAtPath"; | |
1003 | nl[5].n_un.n_name = (char *) "__UIImageWithName"; | |
e6f0817b JF |
1004 | nl[6].n_un.n_name = (char *) "__UIImageWithNameInDomain"; |
1005 | nl[7].n_un.n_name = (char *) "__UIKitBundle"; | |
1006 | nl[8].n_un.n_name = (char *) "__UISharedImageInitialize"; | |
1007 | nl[9].n_un.n_name = (char *) "__UISharedImageNameGetIdentifier"; | |
1008 | nl[10].n_un.n_name = (char *) "__UISharedImageWithIdentifier"; | |
95a5777b JF |
1009 | |
1010 | nlist(UIKit, nl); | |
1011 | ||
1012 | __currentContextCount = (unsigned *) nl[0].n_value; | |
1013 | __currentContextStack = (void ***) nl[1].n_value; | |
1014 | __mappedImages = (id *) nl[2].n_value; | |
1015 | _UIImageAtPath = (UIImage *(*)(NSString *, NSBundle *)) nl[3].n_value; | |
1016 | _UIImageRefAtPath = (CGImageRef *(*)(NSString *, bool, UIImageOrientation *)) nl[4].n_value; | |
1017 | _UIImageWithName = (UIImage *(*)(NSString *)) nl[5].n_value; | |
e6f0817b JF |
1018 | _UIImageWithNameInDomain = (UIImage *(*)(NSString *, NSString *)) nl[6].n_value; |
1019 | _UIKitBundle = (NSBundle *(*)()) nl[7].n_value; | |
1020 | _UISharedImageInitialize = (void (*)(bool)) nl[8].n_value; | |
1021 | _UISharedImageNameGetIdentifier = (int (*)(NSString *)) nl[9].n_value; | |
1022 | _UISharedImageWithIdentifier = (UIImage *(*)(int)) nl[10].n_value; | |
95a5777b | 1023 | |
e6f0817b JF |
1024 | MSHookFunction(_UIImageWithName, &$_UIImageWithName, &_UIImageWithName); |
1025 | MSHookFunction(_UIImageWithNameInDomain, &$_UIImageWithNameInDomain, &_UIImageWithNameInDomain); | |
95a5777b JF |
1026 | |
1027 | if (dlopen(AudioToolbox, RTLD_LAZY | RTLD_NOLOAD) != NULL) { | |
1028 | struct nlist nl[2]; | |
1029 | memset(nl, 0, sizeof(nl)); | |
1030 | nl[0].n_un.n_name = (char *) "__Z24GetFileNameForThisActionmPcRb"; | |
1031 | nlist(AudioToolbox, nl); | |
1032 | _Z24GetFileNameForThisActionmPcRb = (bool (*)(unsigned long, char *, bool &)) nl[0].n_value; | |
e6f0817b | 1033 | MSHookFunction(_Z24GetFileNameForThisActionmPcRb, &$_Z24GetFileNameForThisActionmPcRb, &_Z24GetFileNameForThisActionmPcRb); |
95a5777b | 1034 | } |
2435118f | 1035 | |
e6f0817b JF |
1036 | WBRename(false, "UIImage", @selector(applicationImageNamed:), (IMP) &UIImage$applicationImageNamed$); |
1037 | WBRename(false, "UIImage", @selector(defaultDesktopImage), (IMP) &UIImage$defaultDesktopImage$); | |
1038 | WBRename(false, "UIImage", @selector(imageAtPath:), (IMP) &UIImage$imageAtPath$); | |
1039 | WBRename(false, "UIImage", @selector(imageNamed:), (IMP) &UIImage$imageNamed$); | |
1040 | WBRename(false, "UIImage", @selector(imageNamed:inBundle:), (IMP) &UIImage$imageNamed$inBundle$); | |
1041 | ||
1042 | //WBRename("UINavigationBar", @selector(initWithCoder:", (IMP) &UINavigationBar$initWithCoder$); | |
1043 | //WBRename("UINavigationBarBackground", @selector(initWithFrame:withBarStyle:withTintColor:", (IMP) &UINavigationBarBackground$initWithFrame$withBarStyle$withTintColor$); | |
1044 | //WBRename(true, "SBStatusBar", @selector(initWithMode:orientation:", (IMP) &SBStatusBar$initWithMode$orientation$); | |
1045 | //WBRename(true, "UIWebDocumentView", @selector(setViewportSize:forDocumentTypes:", (IMP) &UIWebDocumentView$setViewportSize$forDocumentTypes$); | |
1046 | ||
1047 | WBRename(true, "NSBundle", @selector(bundlePath), (IMP) &NSBundle$bundlePath$); | |
1048 | WBRename(true, "NSBundle", @selector(pathForResource:ofType:), (IMP) &NSBundle$pathForResource$ofType$); | |
1049 | ||
1050 | WBRename(true, "UIImage", @selector(initWithContentsOfFile:), (IMP) &$initWithContentsOfFile$); | |
1051 | WBRename(true, "UIImage", @selector(initWithContentsOfFile:cache:), (IMP) &UIImage$initWithContentsOfFile$cache$); | |
1052 | WBRename(true, "UINavigationBar", @selector(setBarStyle:), (IMP) &UINavigationBar$setBarStyle$); | |
1053 | WBRename(true, "UIToolbar", @selector(setBarStyle:), (IMP) &UIToolbar$setBarStyle$); | |
1054 | ||
7ff778ee JF |
1055 | WBRename(true, "WebCoreFrameBridge", @selector(renderedSizeOfNode:constrainedToWidth:), (IMP) &WebCoreFrameBridge$renderedSizeOfNode$constrainedToWidth$); |
1056 | ||
4e0efa01 JF |
1057 | WBRename(true, "SBIconModel", @selector(cacheImageForIcon:), (IMP) &SBIconModel$cacheImageForIcon$); |
1058 | WBRename(true, "SBIconModel", @selector(getCachedImagedForIcon:), (IMP) &SBIconModel$getCachedImagedForIcon$); | |
1059 | ||
e6f0817b JF |
1060 | WBRename(true, "SBApplication", @selector(pathForIcon), (IMP) &SBApplication$pathForIcon); |
1061 | WBRename(true, "SBApplicationIcon", @selector(icon), (IMP) &SBApplicationIcon$icon); | |
1062 | WBRename(true, "SBBookmarkIcon", @selector(icon), (IMP) &SBBookmarkIcon$icon); | |
1063 | WBRename(true, "SBButtonBar", @selector(didMoveToSuperview), (IMP) &$didMoveToSuperview); | |
1064 | WBRename(true, "SBCalendarIconContentsView", @selector(drawRect:), (IMP) &SBCalendarIconContentsView$drawRect$); | |
1065 | WBRename(true, "SBContentLayer", @selector(initWithSize:), (IMP) &SBContentLayer$initWithSize$); | |
e6f0817b | 1066 | WBRename(true, "SBIconLabel", @selector(initWithSize:label:), (IMP) &SBIconLabel$initWithSize$label$); |
cf31d246 JF |
1067 | WBRename(true, "SBIconLabel", @selector(setInDock:), (IMP) &SBIconLabel$setInDock$); |
1068 | WBRename(true, "SBIconLabel", @selector(drawRect:), (IMP) &SBIconLabel$drawRect$); | |
e6f0817b JF |
1069 | WBRename(true, "SBSlidingAlertDisplay", @selector(updateDesktopImage:), (IMP) &SBSlidingAlertDisplay$updateDesktopImage$); |
1070 | WBRename(true, "SBStatusBarContentsView", @selector(didMoveToSuperview), (IMP) &$didMoveToSuperview); | |
1071 | WBRename(true, "SBStatusBarContentsView", @selector(initWithStatusBar:mode:), (IMP) &SBStatusBarContentsView$initWithStatusBar$mode$); | |
1072 | WBRename(true, "SBStatusBarController", @selector(setStatusBarMode:orientation:duration:fenceID:animation:), (IMP) &SBStatusBarController$setStatusBarMode$orientation$duration$fenceID$animation$); | |
1073 | WBRename(true, "SBStatusBarTimeView", @selector(drawRect:), (IMP) &SBStatusBarTimeView$drawRect$); | |
1074 | WBRename(true, "SBIconController", @selector(appendIconList:), (IMP) &SBIconController$appendIconList$); | |
d5fb6e01 | 1075 | |
502d350e JF |
1076 | _UISharedImageInitialize(false); |
1077 | ||
1078 | English_ = [[NSDictionary alloc] initWithContentsOfFile:@"/System/Library/CoreServices/SpringBoard.app/English.lproj/LocalizedApplicationNames.strings"]; | |
1079 | if (English_ != nil) | |
1080 | English_ = [English_ retain]; | |
1081 | ||
1082 | Manager_ = [[NSFileManager defaultManager] retain]; | |
1083 | UIImages_ = [[NSMutableDictionary alloc] initWithCapacity:16]; | |
1084 | PathImages_ = [[NSMutableDictionary alloc] initWithCapacity:16]; | |
1085 | Files_ = [[NSMutableDictionary alloc] initWithCapacity:16]; | |
4e0efa01 | 1086 | Cache_ = [[NSMutableDictionary alloc] initWithCapacity:64]; |
502d350e | 1087 | |
d5fb6e01 | 1088 | themes_ = [[NSMutableArray alloc] initWithCapacity:8]; |
26c43b47 | 1089 | |
d5fb6e01 | 1090 | if (NSDictionary *settings = [[NSDictionary alloc] initWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) { |
62b2dbad | 1091 | [settings autorelease]; |
62b2dbad | 1092 | |
95a5777b JF |
1093 | if (NSNumber *debug = [settings objectForKey:@"Debug"]) |
1094 | Debug_ = [debug boolValue]; | |
1095 | ||
d5fb6e01 JF |
1096 | NSArray *themes = [settings objectForKey:@"Themes"]; |
1097 | if (themes == nil) | |
1098 | if (NSString *theme = [settings objectForKey:@"Theme"]) | |
1099 | themes = [NSArray arrayWithObject:[NSDictionary dictionaryWithObjectsAndKeys: | |
1100 | theme, @"Name", | |
95a5777b | 1101 | [NSNumber numberWithBool:true], @"Active", |
d5fb6e01 JF |
1102 | nil]]; |
1103 | if (themes != nil) | |
1104 | for (NSDictionary *theme in themes) { | |
1105 | NSNumber *active = [theme objectForKey:@"Active"]; | |
1106 | if (![active boolValue]) | |
1107 | continue; | |
26c43b47 | 1108 | |
d5fb6e01 JF |
1109 | NSString *name = [theme objectForKey:@"Name"]; |
1110 | if (name == nil) | |
1111 | continue; | |
1112 | ||
1113 | NSString *theme = nil; | |
1114 | ||
95a5777b JF |
1115 | #define testForTheme(format...) \ |
1116 | if (theme == nil) { \ | |
1117 | NSString *path = [NSString stringWithFormat:format]; \ | |
1118 | if ([Manager_ fileExistsAtPath:path]) { \ | |
1119 | [themes_ addObject:path]; \ | |
1120 | continue; \ | |
1121 | } \ | |
d5fb6e01 | 1122 | } |
d5fb6e01 | 1123 | |
95a5777b JF |
1124 | testForTheme(@"/Library/Themes/%@.theme", name) |
1125 | testForTheme(@"/Library/Themes/%@", name) | |
1126 | testForTheme(@"%@/Library/SummerBoard/Themes/%@", NSHomeDirectory(), name) | |
d5fb6e01 | 1127 | } |
26c43b47 JF |
1128 | } |
1129 | ||
d5fb6e01 JF |
1130 | Info_ = [[NSMutableDictionary dictionaryWithCapacity:16] retain]; |
1131 | ||
95a5777b | 1132 | for (NSString *theme in themes_) |
d5fb6e01 JF |
1133 | if (NSDictionary *info = [[NSDictionary alloc] initWithContentsOfFile:[NSString stringWithFormat:@"%@/Info.plist", theme]]) |
1134 | for (NSString *key in [info allKeys]) | |
1135 | if ([Info_ objectForKey:key] == nil) | |
1136 | [Info_ setObject:[info objectForKey:key] forKey:key]; | |
95a5777b JF |
1137 | |
1138 | if (objc_getClass("SpringBoard") != nil) | |
1139 | CFNotificationCenterAddObserver( | |
1140 | CFNotificationCenterGetDarwinNotifyCenter(), | |
1141 | NULL, &ChangeWallpaper, (CFStringRef) @"com.saurik.winterboard.lockbackground", NULL, 0 | |
1142 | ); | |
62b2dbad | 1143 | |
f22a8989 JF |
1144 | if ([Info_ objectForKey:@"UndockedIconLabels"] == nil) |
1145 | [Info_ setObject:[NSNumber numberWithBool:( | |
1146 | [Info_ objectForKey:@"DockedIconLabelStyle"] != nil || | |
1147 | [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil | |
1148 | )] forKey:@"UndockedIconLabels"]; | |
1149 | ||
1150 | if (![Info_ boolForKey:@"UndockedIconLabels"]) | |
d5fb6e01 JF |
1151 | if (Debug_) |
1152 | NSLog(@"WB:Debug:Info = %@", [Info_ description]); | |
1153 | ||
d5168fd6 JF |
1154 | [pool release]; |
1155 | } |