X-Git-Url: https://git.saurik.com/winterboard.git/blobdiff_plain/e079e414fcad2c8b9e164698162e2e3f62d35f61..eae989a318295827259fe347e40918ec59a6ea4a:/Library.mm diff --git a/Library.mm b/Library.mm index bd88130..f3e01ae 100644 --- a/Library.mm +++ b/Library.mm @@ -103,6 +103,8 @@ bool _itv; #include +#include "WBMarkup.h" + extern "C" void __clear_cache (char *beg, char *end); @protocol WinterBoard @@ -113,13 +115,16 @@ Class $MPMoviePlayerController; Class $MPVideoView; MSClassHook(NSBundle) +MSClassHook(NSString) MSClassHook(UIImage) +MSMetaClassHook(UIImage) MSClassHook(UINavigationBar) MSClassHook(UIToolbar) MSClassHook(CKMessageCell) MSClassHook(CKTimestampView) +MSClassHook(CKTranscriptCell) MSClassHook(CKTranscriptController) MSClassHook(CKTranscriptTableView) @@ -128,10 +133,12 @@ MSClassHook(SBApplicationIcon) MSClassHook(SBAwayView) MSClassHook(SBBookmarkIcon) MSClassHook(SBButtonBar) +MSClassHook(SBCalendarApplicationIcon) MSClassHook(SBCalendarIconContentsView) MSClassHook(SBDockIconListView) MSClassHook(SBIcon) MSClassHook(SBIconBadge) +MSClassHook(SBIconBadgeFactory) MSClassHook(SBIconController) MSClassHook(SBIconLabel) MSClassHook(SBIconList) @@ -139,13 +146,17 @@ MSClassHook(SBIconModel) //MSClassHook(SBImageCache) MSClassHook(SBSearchView) MSClassHook(SBSearchTableViewCell) +MSClassHook(SBSlidingAlertDisplay) MSClassHook(SBStatusBarContentsView) MSClassHook(SBStatusBarController) MSClassHook(SBStatusBarOperatorNameView) MSClassHook(SBStatusBarTimeView) MSClassHook(SBUIController) +MSClassHook(SBWallpaperView) MSClassHook(SBWidgetApplicationIcon) +extern "C" void WKSetCurrentGraphicsContext(CGContextRef); + __attribute__((__constructor__)) static void MSFixClass() { if ($SBIcon == nil) @@ -185,6 +196,7 @@ static BOOL (*_GSFontGetUseLegacyFontMetrics)(); (_GSFontGetUseLegacyFontMetrics == NULL ? YES : _GSFontGetUseLegacyFontMetrics()) static bool Debug_ = false; +static bool UIDebug_ = false; static bool Engineer_ = false; static bool SummerBoard_ = true; static bool SpringBoard_; @@ -212,11 +224,23 @@ static NSMutableDictionary *Themed_ = [[NSMutableDictionary alloc] initWithCapac static unsigned Scale_ = 0; -static NSString *$getTheme$(NSArray *files, bool rescale = false) { - if (NSString *path = [Themed_ objectForKey:files]) - return reinterpret_cast(path) == [NSNull null] ? nil : path; +static unsigned $getScale$(NSString *path) { + NSString *name(path); + + #define StripName(strip) \ + if ([name hasSuffix:@ strip]) \ + name = [name substringWithRange:NSMakeRange(0, [name length] - sizeof(strip) - 1)]; + + StripName(".png"); + StripName(".jpg"); + StripName("~iphone"); + StripName("~ipad"); + + return [name hasSuffix:@"@2x"] ? 2 : 1; +} - if (rescale && Scale_ == 0) { +static NSArray *$useScale$(NSArray *files, bool use = true) { + if (Scale_ == 0) { UIScreen *screen([UIScreen mainScreen]); if ([screen respondsToSelector:@selector(scale)]) Scale_ = [screen scale]; @@ -224,6 +248,52 @@ static NSString *$getTheme$(NSArray *files, bool rescale = false) { Scale_ = 1; } + if (Scale_ == 1) + return files; + + NSString *idiom(IsWild_ ? @"ipad" : @"iphone"); + + NSMutableArray *scaled([NSMutableArray arrayWithCapacity:([files count] * 4)]); + + for (NSString *file in files) { + NSString *base([file stringByDeletingPathExtension]); + NSString *extension([file pathExtension]); + + if (use) { + if (Scale_ == 2) { + [scaled addObject:[NSString stringWithFormat:@"%@@2x~%@.%@", base, idiom, extension]]; + if (!IsWild_) + [scaled addObject:[NSString stringWithFormat:@"%@@2x.%@", base, extension]]; + } + + [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]]; + + // if (!IsWild_) <- support old themes + [scaled addObject:file]; + } else if ([base hasSuffix: @"@2x"]) { + [scaled addObject:[NSString stringWithFormat:@"%@~iphone.%@", base, extension]]; + [scaled addObject:file]; + + NSString *rest([base substringWithRange:NSMakeRange(0, [base length] - 3)]); + [scaled addObject:[NSString stringWithFormat:@"%@~iphone.%@", rest, extension]]; + [scaled addObject:[rest stringByAppendingPathExtension:extension]]; + } else { + // XXX: this code isn't really complete + + [scaled addObject:file]; + + if ([base hasSuffix:@"~iphone"]) + [scaled addObject:[[base substringWithRange:NSMakeRange(0, [base length] - 7)] stringByAppendingPathExtension:extension]]; + } + } + + return scaled; +} + +static NSString *$getTheme$(NSArray *files, NSArray *themes = Themes_) { + if (NSString *path = [Themed_ objectForKey:files]) + return reinterpret_cast(path) == [NSNull null] ? nil : path; + if (Debug_) NSLog(@"WB:Debug: %@", [files description]); @@ -271,7 +341,7 @@ static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool u remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock") remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather") - if (NSString *path = $getTheme$(names, ui)) + if (NSString *path = $getTheme$($useScale$(names, ui))) return path; return nil; @@ -362,6 +432,9 @@ static NSString *$pathForIcon$(SBApplication *self, NSString *suffix = @"") { @implementation NSString (WinterBoard) - (NSString *) wb$themedPath { + if ([self hasPrefix:@"/Library/Themes/"]) + return self; + if (Debug_) NSLog(@"WB:Debug:Bypass(\"%@\")", self); @@ -586,6 +659,74 @@ MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, } // }}} +static struct WBStringDrawingState { + WBStringDrawingState *next_; + NSString *base_; + NSString *info_; +} *stringDrawingState_; + +MSInstanceMessageHook4(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode, CGPoint, point, float, width, UIFont *, font, int, mode) { + if (stringDrawingState_ == NULL || stringDrawingState_->info_ == nil) + return MSOldCall(point, width, font, mode); + + NSString *info([Info_ objectForKey:stringDrawingState_->info_]); + if (info == nil) + return MSOldCall(point, width, font, mode); + + NSString *base(stringDrawingState_->base_ ?: @""); + stringDrawingState_ = stringDrawingState_->next_; + + [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]]; + return CGSizeZero; +} + +MSInstanceMessageHook2(CGSize, NSString, drawAtPoint,withFont, CGPoint, point, UIFont *, font) { + if (stringDrawingState_ == NULL || stringDrawingState_->info_ == nil) + return MSOldCall(point, font); + + NSString *info([Info_ objectForKey:stringDrawingState_->info_]); + if (info == nil) + return MSOldCall(point, font); + + NSString *base(stringDrawingState_->base_ ?: @""); + stringDrawingState_ = stringDrawingState_->next_; + + [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]]; + return CGSizeZero; +} + +MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) { + WBStringDrawingState badgeState = {NULL, @"" + "color: white;" + , @"BadgeStyle"}; + + stringDrawingState_ = &badgeState; + + UIImage *image(MSOldCall(text)); + + stringDrawingState_ = NULL; + return image; +} + +MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) { + WBStringDrawingState dayState = {NULL, @"" + "color: white;" + // XXX: this is only correct on an iPod dock + "text-shadow: rgba(0, 0, 0, 0.2) -1px -1px 2px;" + , @"CalendarIconDayStyle"}; + + WBStringDrawingState dateState = {&dayState, @"" + "color: #333333;" + , @"CalendarIconDateStyle"}; + + stringDrawingState_ = &dateState; + + UIImage *image(MSOldCall(type)); + + stringDrawingState_ = NULL; + return image; +} + MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) { NSBundle *bundle([NSBundle mainBundle]); @@ -693,14 +834,6 @@ MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) _SBStatusBarContentsView$didMoveToSuperview(self, sel); } -MSHook(UIImage *, UIImage$defaultDesktopImage, UIImage *self, SEL sel) { - if (Debug_) - NSLog(@"WB:Debug:DefaultDesktopImage"); - if (NSString *path = $getTheme$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil])) - return [UIImage imageWithContentsOfFile:path]; - return _UIImage$defaultDesktopImage(self, sel); -} - static NSArray *Wallpapers_; static bool Papered_; static bool Docked_; @@ -716,34 +849,52 @@ static NSURL *WallpaperURL_; } while (false) static UIImage *$getImage$(NSString *path) { - NSString *name(path); - - #define StripName(strip) \ - if ([name hasSuffix:@ strip]) \ - name = [name substringWithRange:NSMakeRange(0, [name length] - sizeof(strip) - 1)]; - - StripName(".png"); - StripName(".jpg"); - StripName("~iphone"); - StripName("~ipad"); - - unsigned scale([name hasSuffix:@"@2x"] ? 2 : 1); - UIImage *image([UIImage imageWithContentsOfFile:path]); + unsigned scale($getScale$(path)); if (scale != 1 && [image respondsToSelector:@selector(setScale)]) [image setScale:scale]; return image; } +static UIImage *$getDefaultDesktopImage$() { + if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"LockBackground.png", @"LockBackground.jpg", nil]))) + return $getImage$(path); + return nil; +} + +MSClassMessageHook0(UIImage *, UIImage, defaultDesktopImage) { + return $getDefaultDesktopImage$() ?: MSOldCall(); +} + +MSInstanceMessageHook0(UIImage *, SBSlidingAlertDisplay, _defaultDesktopImage) { + return $getDefaultDesktopImage$() ?: MSOldCall(); +} + +MSInstanceMessageHook0(void, SBWallpaperView, resetCurrentImageToWallpaper) { + for (UIView *parent([self superview]); parent != nil; parent = [parent superview]) + if ([parent isKindOfClass:$SBSlidingAlertDisplay]) { + if (UIImage *image = $getDefaultDesktopImage$()) { + [self setImage:image]; + return; + } + + break; + } + + MSOldCall(); +} + // %hook -[SBUIController init] {{{ MSInstanceMessageHook0(id, SBUIController, init) { self = MSOldCall(); if (self == nil) return nil; - NSString *paper($getTheme$(Wallpapers_, true)); + NSString *paper($getTheme$(Wallpapers_)); + if (paper != nil) + paper = [paper stringByDeletingLastPathComponent]; { size_t size; @@ -825,8 +976,10 @@ MSInstanceMessageHook0(id, SBUIController, init) { _release(WallpaperPage_); _release(WallpaperURL_); - if (NSString *path = paper) { - if ([path hasSuffix:@".mp4"]) { + if (paper != nil) { + NSArray *themes([NSArray arrayWithObject:paper]); + + if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.mp4"], themes)) { #if UseAVController NSError *error; @@ -861,7 +1014,7 @@ MSInstanceMessageHook0(id, SBUIController, init) { [indirect addSubview:video]; } - if ([path hasSuffix:@".png"] || [path hasSuffix:@".jpg"]) { + if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"Wallpaper.png", @"Wallpaper.jpg", nil]), themes)) { if (UIImage *image = $getImage$(path)) { WallpaperFile_ = [path retain]; WallpaperImage_ = [[UIImageView alloc] initWithImage:image]; @@ -871,7 +1024,7 @@ MSInstanceMessageHook0(id, SBUIController, init) { } } - if ([path hasSuffix:@".html"]) { + if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) { CGRect bounds = [indirect bounds]; UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]); @@ -1288,7 +1441,7 @@ MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constraine } // }}} -MSHook(void, SBIconLabel$drawRect$, SBIconLabel *self, SEL sel, CGRect rect) { +MSInstanceMessageHook1(void, SBIconLabel, drawRect, CGRect, rect) { CGRect bounds = [self bounds]; static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL); @@ -1314,7 +1467,7 @@ MSHook(void, SBIconLabel$drawRect$, SBIconLabel *self, SEL sel, CGRect rect) { style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "]; bool ellipsis(false); - float max = 75, width; + float max = [self frame].size.width - 11, width; width: width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width; @@ -1347,8 +1500,20 @@ MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, bal [balloon setBackgroundColor:[UIColor clearColor]]; } +MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) { + MSOldCall([UIColor clearColor]); +} + +MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) { + if ((self = MSOldCall(style, reuse)) != nil) { + [self setBackgroundColor:[UIColor clearColor]]; + [[self contentView] setBackgroundColor:[UIColor clearColor]]; + } return self; +} + MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) { if ((self = MSOldCall(style, reuse)) != nil) { + [self setBackgroundColor:[UIColor clearColor]]; [[self contentView] setBackgroundColor:[UIColor clearColor]]; } return self; } @@ -1373,10 +1538,8 @@ MSInstanceMessageHook2(id, CKTranscriptTableView, initWithFrame,style, CGRect, f MSInstanceMessageHook0(void, CKTranscriptController, loadView) { MSOldCall(); - if (NSString *path = $getTheme$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil])) - if (UIImage *image = [[UIImage alloc] initWithContentsOfFile:path]) { - [image autorelease]; - + if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil]))) + if (UIImage *image = $getImage$(path)) { UIView *&_transcriptTable(MSHookIvar(self, "_transcriptTable")); UIView *&_transcriptLayer(MSHookIvar(self, "_transcriptLayer")); UIView *table; @@ -1430,13 +1593,21 @@ MSHook(UIImage *, _UIImageWithName, NSString *name) { UIImage *image([UIImages_ objectForKey:key]); if (image != nil) return reinterpret_cast(image) == [NSNull null] ? __UIImageWithName(name) : image; - if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true)) { - image = [[UIImage alloc] initWithContentsOfFile:path cache:true]; - if (image != nil) - [image autorelease]; - } + if (NSString *path = $pathForFile$inBundle$(name, _UIKitBundle(), true)) + image = $getImage$(path); [UIImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast(image)) forKey:key]; - return image == nil ? __UIImageWithName(name) : image; + if (image != nil) + return image; + + image = __UIImageWithName(name); + + if (UIDebug_) { + NSString *path([@"/tmp/UIImages/" stringByAppendingString:name]); + if (![Manager_ fileExistsAtPath:path]) + [UIImagePNGRepresentation(image) writeToFile:path atomically:YES]; + } + + return image; } } // }}} @@ -1448,11 +1619,8 @@ MSHook(UIImage *, _UIImageWithNameInDomain, NSString *name, NSString *domain) { return reinterpret_cast(image) == [NSNull null] ? __UIImageWithNameInDomain(name, domain) : image; if (Debug_) NSLog(@"WB:Debug: UIImageWithNameInDomain(\"%@\", \"%@\")", name, domain); - if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]], true)) { - image = [[UIImage alloc] initWithContentsOfFile:path]; - if (image != nil) - [image autorelease]; - } + if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObject:[NSString stringWithFormat:@"Domains/%@/%@", domain, name]]))) + image = $getImage$(path); [PathImages_ setObject:(image == nil ? [NSNull null] : reinterpret_cast(image)) forKey:key]; return image == nil ? __UIImageWithNameInDomain(name, domain) : image; } @@ -1555,10 +1723,22 @@ MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) { } // }}} -static void SBInitialize() { - _UIImage$defaultDesktopImage = MSHookMessage(object_getClass($UIImage), @selector(defaultDesktopImage), &$UIImage$defaultDesktopImage); +static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint point, NSString *style) { + WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext()); + if (style == nil || [style length] == 0) + style = @"font-family: Helvetica; font-size: 12px"; + return [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style]; +} - bool olden(dlsym(RTLD_DEFAULT, "GSLibraryCopyGenerationInfoValueForKey") == NULL); +static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSString *style, float width) { + if (style == nil || [style length] == 0) + style = @"font-family: Helvetica; font-size: 12px"; + return [[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width]; +} + +static void SBInitialize() { + class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16"); + class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12"); if (SummerBoard_) { WBRename(SBApplication, pathForIcon, pathForIcon); @@ -1577,9 +1757,6 @@ static void SBInitialize() { WBRename(SBDockIconListView, setFrame:, setFrame$); MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock); - if (olden) - WBRename(SBIconLabel, drawRect:, drawRect$); - WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$); WBRename(SBIconLabel, setInDock:, setInDock$); @@ -1694,7 +1871,7 @@ MSInitialize { // }}} // SpringBoard {{{ if (SpringBoard_) { - Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain]; + Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain]; Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]); CFNotificationCenterAddObserver( @@ -1737,5 +1914,8 @@ MSInitialize { } // }}} + if (Debug_ && [Manager_ fileExistsAtPath:@"/tmp/UIImages"]) + UIDebug_ = true; + [pool release]; }