X-Git-Url: https://git.saurik.com/winterboard.git/blobdiff_plain/e965c1e5c828ed9a5d03a2448524fc67c9bef226..c40f4c119a37f0ce071b3253dc6ef89a6dfe28d8:/Library.mm?ds=sidebyside diff --git a/Library.mm b/Library.mm index fa44fbb..2744675 100644 --- a/Library.mm +++ b/Library.mm @@ -47,7 +47,7 @@ bool _itv; _itv = true; \ _ltv = _ctv; \ } \ - NSLog(@"%lu.%.6u[%f]:_trace()@%s:%u[%s]\n", \ + NSLog(@"%lu.%.6u[%f]:WB:_trace()@%s:%u[%s]\n", \ _ctv.tv_sec, _ctv.tv_usec, \ (_ctv.tv_sec - _ltv.tv_sec) + (_ctv.tv_usec - _ltv.tv_usec) / 1000000.0, \ __FILE__, __LINE__, __FUNCTION__\ @@ -107,6 +107,10 @@ bool _itv; extern "C" void __clear_cache (char *beg, char *end); +static void (*$objc_setAssociatedObject)(id object, void *key, id value, objc_AssociationPolicy policy); +static id (*$objc_getAssociatedObject)(id object, void *key); +static void (*$objc_removeAssociatedObjects)(id object); + @protocol WinterBoard - (void *) _node; @end @@ -121,11 +125,15 @@ MSClassHook(UIImage) MSMetaClassHook(UIImage) MSClassHook(UINavigationBar) MSClassHook(UIToolbar) +MSClassHook(UIStatusBarTimeItemView) +MSClassHook(UIWebDocumentView) +MSClassHook(CKBalloonView) MSClassHook(CKMessageCell) MSClassHook(CKTimestampView) MSClassHook(CKTranscriptCell) MSClassHook(CKTranscriptController) +MSClassHook(CKTranscriptHeaderView) MSClassHook(CKTranscriptTableView) MSClassHook(SBApplication) @@ -137,12 +145,21 @@ MSClassHook(SBCalendarApplicationIcon) MSClassHook(SBCalendarIconContentsView) MSClassHook(SBDockIconListView) MSClassHook(SBIcon) +MSClassHook(SBIconAccessoryImage) +MSMetaClassHook(SBIconAccessoryImage) MSClassHook(SBIconBadge) MSClassHook(SBIconBadgeFactory) +MSClassHook(SBIconBadgeImage) +MSClassHook(SBIconContentView) MSClassHook(SBIconController) MSClassHook(SBIconLabel) +MSClassHook(SBIconLabelImage) +MSMetaClassHook(SBIconLabelImage) +MSClassHook(SBIconLabelImageParameters) MSClassHook(SBIconList) MSClassHook(SBIconModel) +MSClassHook(SBIconView) +MSMetaClassHook(SBIconView) //MSClassHook(SBImageCache) MSClassHook(SBSearchView) MSClassHook(SBSearchTableViewCell) @@ -157,17 +174,23 @@ MSClassHook(SBWidgetApplicationIcon) extern "C" void WKSetCurrentGraphicsContext(CGContextRef); -__attribute__((__constructor__)) -static void MSFixClass() { - if ($SBIcon == nil) - $SBIcon = objc_getClass("SBIconView"); +static struct MSFixClass { MSFixClass() { + $UIWebDocumentView = objc_getClass("UIWebBrowserView") ?: $UIWebDocumentView; + $SBIcon = objc_getClass("SBIconView") ?: $SBIcon; + + if ($SBIconList == nil) + $SBIconList = objc_getClass("SBIconListView"); if ($CKTranscriptController == nil) $CKTranscriptController = objc_getClass("mSMSMessageTranscriptController"); -} +} } MSFixClass; static bool IsWild_; static bool Four_($SBDockIconListView != nil); +@interface NSObject (wb$SBIconAccessoryImage) ++ (Class) _imageClassForIcon:(SBIcon *)icon location:(int)location; +@end + @interface NSDictionary (WinterBoard) - (UIColor *) wb$colorForKey:(NSString *)key; - (BOOL) wb$boolForKey:(NSString *)key; @@ -198,7 +221,7 @@ static BOOL (*_GSFontGetUseLegacyFontMetrics)(); static bool Debug_ = false; static bool UIDebug_ = false; static bool Engineer_ = false; -static bool SummerBoard_ = true; +static bool SummerBoard_ = false; static bool SpringBoard_; static UIImage *(*_UIApplicationImageWithName)(NSString *name); @@ -240,7 +263,7 @@ static unsigned $getScale$(NSString *path) { } static NSArray *$useScale$(NSArray *files, bool use = true) { - if (Scale_ == 0) { + if (use && Scale_ == 0) { UIScreen *screen([UIScreen mainScreen]); if ([screen respondsToSelector:@selector(scale)]) Scale_ = [screen scale]; @@ -262,8 +285,7 @@ static NSArray *$useScale$(NSArray *files, bool use = true) { 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:@"%@@2x.%@", base, extension]]; } [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, extension]]; @@ -271,19 +293,20 @@ static NSArray *$useScale$(NSArray *files, bool use = true) { // if (!IsWild_) <- support old themes [scaled addObject:file]; } else if ([base hasSuffix: @"@2x"]) { - [scaled addObject:[NSString stringWithFormat:@"%@~iphone.%@", base, extension]]; + [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", base, idiom, 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]]; + // XXX: this actually can't be used, as the person loading the file doesn't realize that the @2x changed + /*NSString *rest([base substringWithRange:NSMakeRange(0, [base length] - 3)]); + [scaled addObject:[NSString stringWithFormat:@"%@~%@.%@", rest, idiom, 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]]; + if ([base hasSuffix:[NSString stringWithFormat:@"~%@", idiom]]) + [scaled addObject:[[base substringWithRange:NSMakeRange(0, [base length] - 1 - [idiom length])] stringByAppendingPathExtension:extension]]; } } @@ -291,8 +314,13 @@ static NSArray *$useScale$(NSArray *files, bool use = true) { } static NSString *$getTheme$(NSArray *files, NSArray *themes = Themes_) { - if (NSString *path = [Themed_ objectForKey:files]) - return reinterpret_cast(path) == [NSNull null] ? nil : path; + // XXX: this is not reasonable; OMG + id key(files); + + @synchronized (Themed_) { + if (NSString *path = [Themed_ objectForKey:key]) + return reinterpret_cast(path) == [NSNull null] ? nil : path; + } if (Debug_) NSLog(@"WB:Debug: %@", [files description]); @@ -302,14 +330,20 @@ static NSString *$getTheme$(NSArray *files, NSArray *themes = Themes_) { for (NSString *theme in Themes_) for (NSString *file in files) { path = [NSString stringWithFormat:@"%@/%@", theme, file]; - if ([Manager_ fileExistsAtPath:path]) + if ([Manager_ fileExistsAtPath:path]) { + if ([[Manager_ pathContentOfSymbolicLinkAtPath:path] isEqualToString:@"/"]) + path = nil; goto set; + } } path = nil; set: - [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast(path)) forKey:files]; + @synchronized (Themed_) { + [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast(path)) forKey:key]; + } + return path; } // }}} @@ -320,8 +354,14 @@ static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool u if (identifier != nil) [names addObject:[NSString stringWithFormat:@"Bundles/%@/%@", identifier, file]]; - if (NSString *folder = [[bundle bundlePath] lastPathComponent]) + if (NSString *folder = [[bundle bundlePath] lastPathComponent]) { [names addObject:[NSString stringWithFormat:@"Folders/%@/%@", folder, file]]; + NSString *base([folder stringByDeletingPathExtension]); + if ([base hasSuffix:@"~iphone"]) + [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 7)], [folder pathExtension], file]]; + if ([base hasSuffix:@"~ipad"]) + [names addObject:[NSString stringWithFormat:@"Folders/%@.%@/%@", [base substringWithRange:NSMakeRange(0, [base length] - 5)], [folder pathExtension], file]]; + } if (ui) [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]]; @@ -341,6 +381,8 @@ static NSString *$pathForFile$inBundle$(NSString *file, NSBundle *bundle, bool u remapResourceName(Four_ ? @"SBDockBG-old.png" : @"SBDockBG.png", @"Dock") remapResourceName(@"SBWeatherCelsius.png", @"Icons/Weather") + [names addObject:[NSString stringWithFormat:@"Fallback/%@", file]]; + if (NSString *path = $getTheme$($useScale$(names, ui))) return path; @@ -659,45 +701,211 @@ MSInstanceMessageHook2(NSString *, NSBundle, pathForResource,ofType, NSString *, } // }}} +static void $drawLabel$(NSString *label, CGRect rect, NSString *style, NSString *custom) { + bool ellipsis(false); + float max = rect.size.width - 11, width; + width: + width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width; + + if (width > max) { + size_t length([label length]); + float spacing((width - max) / (length - 1)); + + if (spacing > 1.25) { + ellipsis = true; + label = [label substringToIndex:(length - 1)]; + goto width; + } + + style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]]; + } + + if (ellipsis) + label = [label stringByAppendingString:@"..."]; + + if (custom != nil) + style = [style stringByAppendingString:custom]; + + CGSize size = [label sizeWithStyle:style forWidth:rect.size.width]; + [label drawAtPoint:CGPointMake((rect.size.width - size.width) / 2 + rect.origin.x, rect.origin.y) withStyle:style]; +} + static struct WBStringDrawingState { WBStringDrawingState *next_; + unsigned count_; 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); +extern "C" CGColorSpaceRef CGContextGetFillColorSpace(CGContextRef); +extern "C" void CGContextGetFillColor(CGContextRef, CGFloat[]); + +static NSString *WBColorMarkup() { + CGContextRef context(UIGraphicsGetCurrentContext()); + //NSLog(@"XXX:1:%p", context); + if (context == NULL) + return @""; + + CGColorSpaceRef space(CGContextGetFillColorSpace(context)); + //NSLog(@"XXX:2:%p", space); + if (space == NULL) + return @""; + + size_t number(CGColorSpaceGetNumberOfComponents(space)); + //NSLog(@"XXX:3:%u", number); + if (number == 0) + return @""; + + CGFloat components[number + 1]; + CGContextGetFillColor(context, components); + + CGFloat r, g, b, a; + + switch (number) { + case 1: + r = components[0]; + g = components[0]; + b = components[0]; + a = components[1]; + break; + + case 3: + r = components[0]; + g = components[1]; + b = components[2]; + a = components[3]; + break; + + default: + return @""; + } - NSString *info([Info_ objectForKey:stringDrawingState_->info_]); - if (info == nil) - return MSOldCall(point, width, font, mode); + return [NSString stringWithFormat:@"color: rgba(%g, %g, %g, %g)", r * 255, g * 255, b * 255, a]; +} + +MSInstanceMessageHook6(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode,letterSpacing,includeEmoji, CGPoint, point, float, width, UIFont *, font, UILineBreakMode, mode, float, spacing, BOOL, emoji) { + //NSLog(@"XXX: @\"%@\" %g", self, spacing); + + WBStringDrawingState *state(stringDrawingState_); + if (state == NULL) + return MSOldCall(point, width, font, mode, spacing, emoji); + + if (--state->count_ == 0) + stringDrawingState_ = state->next_; + if (state->info_ == nil) + return MSOldCall(point, width, font, mode, spacing, emoji); - NSString *base(stringDrawingState_->base_ ?: @""); - stringDrawingState_ = stringDrawingState_->next_; + NSString *info([Info_ objectForKey:state->info_]); + if (info == nil) + return MSOldCall(point, width, font, mode, spacing, emoji); - [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]]; + NSString *base(state->base_ ?: @""); + NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]); + [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]]; return CGSizeZero; } -MSInstanceMessageHook2(CGSize, NSString, drawAtPoint,withFont, CGPoint, point, UIFont *, font) { - if (stringDrawingState_ == NULL || stringDrawingState_->info_ == nil) - return MSOldCall(point, font); +extern "C" NSString *NSStringFromCGRect(CGRect rect); + +MSInstanceMessageHook7(CGSize, NSString, _drawInRect,withFont,lineBreakMode,alignment,lineSpacing,includeEmoji,truncationRect, CGRect, rect, UIFont *, font, UILineBreakMode, mode, UITextAlignment, alignment, float, spacing, BOOL, emoji, CGRect, truncation) { + //NSLog(@"XXX: &\"%@\" %@ \"%@\" %u %u %g %u %@", self, NSStringFromCGRect(rect), font, mode, alignment, spacing, emoji, NSStringFromCGRect(truncation)); + + WBStringDrawingState *state(stringDrawingState_); + if (state == NULL) + return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation); - NSString *info([Info_ objectForKey:stringDrawingState_->info_]); + if (--state->count_ == 0) + stringDrawingState_ = state->next_; + if (state->info_ == nil) + return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation); + + NSString *info([Info_ objectForKey:state->info_]); if (info == nil) - return MSOldCall(point, font); + return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation); - NSString *base(stringDrawingState_->base_ ?: @""); - stringDrawingState_ = stringDrawingState_->next_; + NSString *textAlign; + switch (alignment) { + default: + case UITextAlignmentLeft: + textAlign = @"left"; + break; + case UITextAlignmentCenter: + textAlign = @"center"; + break; + case UITextAlignmentRight: + textAlign = @"right"; + break; + } + + NSString *base(state->base_ ?: @""); + NSString *extra([NSString stringWithFormat:@"text-align: %@", textAlign]); + + if (true) + $drawLabel$(self, rect, [NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], WBColorMarkup(), base], info); + else + [self drawInRect:rect withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info]]; - [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]]; return CGSizeZero; } +MSInstanceMessageHook4(CGSize, NSString, sizeWithFont,forWidth,lineBreakMode,letterSpacing, UIFont *, font, float, width, UILineBreakMode, mode, float, spacing) { + //NSLog(@"XXX: #\"%@\" \"%@\" %g %u %g", self, font, width, mode, spacing); + + WBStringDrawingState *state(stringDrawingState_); + if (state == NULL) + return MSOldCall(font, width, mode, spacing); + + if (--state->count_ == 0) + stringDrawingState_ = state->next_; + if (state->info_ == nil) + return MSOldCall(font, width, mode, spacing); + + NSString *info([Info_ objectForKey:state->info_]); + if (info == nil) + return MSOldCall(font, width, mode, spacing); + + NSString *base(state->base_ ?: @""); + NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]); + return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), extra, base, info] forWidth:width]; +} + +MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) { + //NSLog(@"XXX: ?\"%@\"", self); + + WBStringDrawingState *state(stringDrawingState_); + if (state == NULL) + return MSOldCall(font); + + if (--state->count_ == 0) + stringDrawingState_ = state->next_; + if (state->info_ == nil) + return MSOldCall(font); + + NSString *info([Info_ objectForKey:state->info_]); + if (info == nil) + return MSOldCall(font); + + NSString *base(state->base_ ?: @""); + return [self sizeWithStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], WBColorMarkup(), base, info] forWidth:65535]; +} + +MSClassMessageHook2(UIImage *, SBIconAccessoryImage, checkoutAccessoryImageForIcon,location, id, icon, int, location) { + if ([self _imageClassForIcon:icon location:location] != $SBIconBadgeImage) + return MSOldCall(icon, location); + + WBStringDrawingState badgeState = {NULL, -1, @"" + , @"BadgeStyle"}; + + stringDrawingState_ = &badgeState; + + UIImage *image(MSOldCall(icon, location)); + + stringDrawingState_ = NULL; + return image; +} + MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, NSString *, text) { - WBStringDrawingState badgeState = {NULL, @"" - "color: white;" + WBStringDrawingState badgeState = {NULL, -1, @"" , @"BadgeStyle"}; stringDrawingState_ = &badgeState; @@ -709,14 +917,14 @@ MSInstanceMessageHook1(UIImage *, SBIconBadgeFactory, checkoutBadgeImageForText, } MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, int, type) { - WBStringDrawingState dayState = {NULL, @"" - "color: white;" + WBStringDrawingState dayState = {NULL, 2, @"" // 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;" + WBStringDrawingState sizeState = {&dayState, 7, nil, nil}; + + WBStringDrawingState dateState = {&sizeState, 2, @"" , @"CalendarIconDateStyle"}; stringDrawingState_ = &dateState; @@ -727,6 +935,18 @@ MSInstanceMessageHook1(UIImage *, SBCalendarApplicationIcon, generateIconImage, return image; } +MSInstanceMessageHook1(UIImage *, UIStatusBarTimeItemView, contentsImageForStyle, int, style) { + WBStringDrawingState timeState = {NULL, 0, @"" + , @"TimeStyle"}; + + stringDrawingState_ = &timeState; + + UIImage *image(MSOldCall(style)); + + stringDrawingState_ = NULL; + return image; +} + MSHook(void, SBCalendarIconContentsView$drawRect$, SBCalendarIconContentsView *self, SEL sel, CGRect rect) { NSBundle *bundle([NSBundle mainBundle]); @@ -837,6 +1057,7 @@ MSHook(void, SBStatusBarContentsView$didMoveToSuperview, UIView *self, SEL sel) static NSArray *Wallpapers_; static bool Papered_; static bool Docked_; +static bool SMSBackgrounded_; static NSString *WallpaperFile_; static UIImageView *WallpaperImage_; static UIWebDocumentView *WallpaperPage_; @@ -910,15 +1131,6 @@ MSInstanceMessageHook0(id, SBUIController, init) { IsWild_ = machine != NULL && strncmp(machine, "iPad", 4) == 0; } - BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast(dlsym(RTLD_DEFAULT, "GSSystemHasCapability")); - - if ([Info_ objectForKey:@"UndockedIconLabels"] == nil) - [Info_ setObject:[NSNumber numberWithBool:( - !(paper != nil || GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper"))) || - [Info_ objectForKey:@"DockedIconLabelStyle"] != nil || - [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil - )] forKey:@"UndockedIconLabels"]; - if (Debug_) NSLog(@"WB:Debug:Info = %@", [Info_ description]); @@ -1027,7 +1239,7 @@ MSInstanceMessageHook0(id, SBUIController, init) { if (NSString *path = $getTheme$([NSArray arrayWithObject:@"Wallpaper.html"], themes)) { CGRect bounds = [indirect bounds]; - UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]); + UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]); [view setAutoresizes:true]; WallpaperPage_ = [view retain]; @@ -1050,7 +1262,7 @@ MSInstanceMessageHook0(id, SBUIController, init) { if ([Manager_ fileExistsAtPath:html]) { CGRect bounds = [indirect bounds]; - UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]); + UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]); [view setAutoresizes:true]; NSURL *url = [NSURL fileURLWithPath:html]; @@ -1081,7 +1293,7 @@ MSHook(void, SBAwayView$updateDesktopImage$, SBAwayView *self, SEL sel, UIImage if (path != nil) { CGRect bounds = [self bounds]; - UIWebDocumentView *view([[[UIWebDocumentView alloc] initWithFrame:bounds] autorelease]); + UIWebDocumentView *view([[[$UIWebDocumentView alloc] initWithFrame:bounds] autorelease]); [view setAutoresizes:true]; if (WallpaperPage_ != nil) @@ -1135,7 +1347,7 @@ extern "C" NSString *UIStyleStringFromColor(CGColorRef);*/ WBDelegate(time_) -- (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode { +- (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode { if (NSString *custom = [Info_ objectForKey:@"TimeStyle"]) { BOOL &_mode(MSHookIvar(view_, "_mode"));; @@ -1182,7 +1394,7 @@ WBDelegate(time_) WBDelegate(badge_) -- (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(int)mode { +- (CGSize) drawAtPoint:(CGPoint)point forWidth:(float)width withFont:(UIFont *)font lineBreakMode:(UILineBreakMode)mode { if (NSString *custom = [Info_ objectForKey:@"BadgeStyle"]) { [badge_ drawAtPoint:point withStyle:[NSString stringWithFormat:@"" "font-family: Helvetica; " @@ -1218,8 +1430,12 @@ MSInstanceMessageHook0(id, SBIcon, initWithDefaultSize) { if (NSNumber *number = [Info_ objectForKey:@"IconAlpha"]) { // XXX: note: this is overridden above, which is silly float alpha([number floatValue]); - [self setIconImageAlpha:alpha]; - [self setIconLabelAlpha:alpha]; + if ([self respondsToSelector:@selector(setIconImageAlpha:)]) + [self setIconImageAlpha:alpha]; + if ([self respondsToSelector:@selector(setIconLabelAlpha:)]) + [self setIconLabelAlpha:alpha]; + if ([self respondsToSelector:@selector(setAlpha:)]) + [self setAlpha:alpha]; } } return self; } @@ -1299,6 +1515,7 @@ MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, @interface UIView (WinterBoard) - (bool) wb$isWBImageView; - (void) wb$logHierarchy; +- (void) wb$setBackgroundColor:(UIColor *)color; @end @implementation UIView (WinterBoard) @@ -1311,6 +1528,12 @@ MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, WBLogHierarchy(self); } +- (void) wb$setBackgroundColor:(UIColor *)color { + [self setBackgroundColor:color]; + for (UIView *child in [self subviews]) + [child wb$setBackgroundColor:color]; +} + @end @interface WBImageView : UIImageView { @@ -1342,39 +1565,70 @@ MSHook(void, SBStatusBarTimeView$drawRect$, SBStatusBarTimeView *self, SEL sel, @end -MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) { +static void SBIconList$updateFrames$(SBIconList *self) { NSArray *subviews([self subviews]); WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]); if (view != nil && [view wb$isWBImageView]) [view wb$updateFrame]; +} + +MSHook(void, SBIconList$didMoveToSuperview, SBIconList *self, SEL sel) { + SBIconList$updateFrames$(self); + _SBIconList$didMoveToSuperview(self, sel); +} + +MSHook(void, SBIconList$setFrame$, SBIconList *self, SEL sel, CGRect frame) { + SBIconList$updateFrames$(self); _SBIconList$setFrame$(self, sel, frame); } -MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) { - SBIconModel *&_iconModel(MSHookIvar(self, "_iconModel")); - NSArray *lists([_iconModel iconLists]); +static void $addPerPageView$(unsigned i, UIView *list) { + NSString *path($getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]])); + if (path == nil) + return; + + NSArray *subviews([list subviews]); + + WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]); + if (view == nil || ![view wb$isWBImageView]) { + view = [[[WBImageView alloc] init] autorelease]; + [list insertSubview:view atIndex:0]; + } + + UIImage *image([UIImage imageWithContentsOfFile:path]); + + CGRect frame([view frame]); + frame.size = [image size]; + [view setFrame:frame]; + [view setImage:image]; + [view wb$updateFrame]; +} + +static void $addPerPageViews$(NSArray *lists) { for (unsigned i(0), e([lists count]); i != e; ++i) - if (NSString *path = $getTheme$([NSArray arrayWithObject:[NSString stringWithFormat:@"Page%u.png", i]])) { - SBIconList *list([lists objectAtIndex:i]); - NSArray *subviews([list subviews]); - - WBImageView *view([subviews count] == 0 ? nil : [subviews objectAtIndex:0]); - if (view == nil || ![view wb$isWBImageView]) { - view = [[[WBImageView alloc] init] autorelease]; - [list insertSubview:view atIndex:0]; - } + $addPerPageView$(i, [lists objectAtIndex:i]); +} - UIImage *image([UIImage imageWithContentsOfFile:path]); +MSInstanceMessageHook0(void, SBIconController, updateNumberOfRootIconLists) { + NSArray *&_rootIconLists(MSHookIvar(self, "_rootIconLists")); + $addPerPageViews$(_rootIconLists); + return MSOldCall(); +} - CGRect frame([view frame]); - frame.size = [image size]; - [view setFrame:frame]; +MSInstanceMessageHook0(void, SBIconContentView, layoutSubviews) { + MSOldCall(); - [view setImage:image]; - [view wb$updateFrame]; - } + if (SBIconController *controller = [$SBIconController sharedInstance]) { + UIView *&_dockContainerView(MSHookIvar(controller, "_dockContainerView")); + if (&_dockContainerView != NULL) + [[_dockContainerView superview] bringSubviewToFront:_dockContainerView]; + } +} +MSHook(void, SBIconController$noteNumberOfIconListsChanged, SBIconController *self, SEL sel) { + SBIconModel *&_iconModel(MSHookIvar(self, "_iconModel")); + $addPerPageViews$([_iconModel iconLists]); return _SBIconController$noteNumberOfIconListsChanged(self, sel); } @@ -1386,6 +1640,20 @@ MSHook(id, SBIconLabel$initWithSize$label$, SBIconLabel *self, SEL sel, CGSize s } MSHook(void, SBIconLabel$setInDock$, SBIconLabel *self, SEL sel, BOOL docked) { + static bool gssc(false); + if (!gssc) { + BOOL (*GSSystemHasCapability)(CFStringRef) = reinterpret_cast(dlsym(RTLD_DEFAULT, "GSSystemHasCapability")); + Papered_ |= GSSystemHasCapability != NULL && GSSystemHasCapability(CFSTR("homescreen-wallpaper")); + gssc = true; + + if ([Info_ objectForKey:@"UndockedIconLabels"] == nil) + [Info_ setObject:[NSNumber numberWithBool:( + !Papered_ || + [Info_ objectForKey:@"DockedIconLabelStyle"] != nil || + [Info_ objectForKey:@"UndockedIconLabelStyle"] != nil + )] forKey:@"UndockedIconLabels"]; + } + id &_label(MSHookIvar(self, "_label")); if (![Info_ wb$boolForKey:@"UndockedIconLabels"]) docked = true; @@ -1444,9 +1712,7 @@ MSInstanceMessageHook2(CGSize, WebCoreFrameBridge, renderedSizeOfNode,constraine } // }}} -MSInstanceMessageHook1(void, SBIconLabel, drawRect, CGRect, rect) { - CGRect bounds = [self bounds]; - +MSInstanceMessage1(void, SBIconLabel, drawRect, CGRect, rect) { static Ivar drawMoreLegibly = object_getInstanceVariable(self, "_drawMoreLegibly", NULL); int docked; @@ -1469,35 +1735,74 @@ MSInstanceMessageHook1(void, SBIconLabel, drawRect, CGRect, rect) { else if (docked) style = [style stringByAppendingString:@"text-shadow: rgba(0, 0, 0, 0.5) 0px -1px 0px; "]; - bool ellipsis(false); - float max = [self frame].size.width - 11, width; - width: - width = [(ellipsis ? [label stringByAppendingString:@"..."] : label) sizeWithStyle:style forWidth:320].width; + NSString *custom([Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")]); - if (width > max) { - size_t length([label length]); - float spacing((width - max) / (length - 1)); + $drawLabel$(label, [self bounds], style, custom); +} - if (spacing > 1.25) { - ellipsis = true; - label = [label substringToIndex:(length - 1)]; - goto width; - } +MSInstanceMessage0(CGImageRef, SBIconLabel, buildLabelImage) { + bool docked((MSHookIvar(self, "_inDock") & 0x2) != 0); - style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]]; - } + WBStringDrawingState labelState = {NULL, 0, @"" + , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"}; - if (ellipsis) - label = [label stringByAppendingString:@"..."]; + stringDrawingState_ = &labelState; - if (NSString *custom = [Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")]) - style = [style stringByAppendingString:custom]; + //NSLog(@"XXX: +"); + CGImageRef image(MSOldCall()); + //NSLog(@"XXX: -"); + + stringDrawingState_ = NULL; + return image; +} + +static bool wb$inDock(id parameters) { + return [$objc_getAssociatedObject(parameters, @selector(wb$inDock)) boolValue]; +} + +MSInstanceMessage0(NSUInteger, SBIconLabelImageParameters, hash) { + return MSOldCall() + (wb$inDock(self) ? 0xdeadbeef : 0xd15ea5e); +} - CGSize size = [label sizeWithStyle:style forWidth:bounds.size.width]; - [label drawAtPoint:CGPointMake((bounds.size.width - size.width) / 2, 0) withStyle:style]; +MSClassMessage2(id, SBIconView, _labelImageParametersForIcon,location, id, icon, int, location) { + if (id parameters = MSOldCall(icon, location)) { + $objc_setAssociatedObject(parameters, @selector(wb$inDock), [NSNumber numberWithBool:(location == 1)], OBJC_ASSOCIATION_RETAIN_NONATOMIC); + return parameters; + } return nil; +} + +MSClassMessage1(UIImage *, SBIconLabelImage, _drawLabelImageForParameters, id, parameters) { + bool docked(wb$inDock(parameters)); + + WBStringDrawingState labelState = {NULL, 0, @"" + , docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"}; + + stringDrawingState_ = &labelState; + + //NSLog(@"XXX: +"); + UIImage *image(MSOldCall(parameters)); + //NSLog(@"XXX: -"); + + stringDrawingState_ = NULL; + return image; } // ChatKit {{{ +MSInstanceMessageHook2(id, CKBalloonView, initWithFrame,delegate, CGRect, frame, id, delegate) { + if ((self = MSOldCall(frame, delegate)) != nil) { + [self setBackgroundColor:[UIColor clearColor]]; + } return self; +} + +MSInstanceMessageHook0(BOOL, CKBalloonView, _canUseLayerBackedBalloon) { + return SMSBackgrounded_ ? NO : MSOldCall(); +} + +MSInstanceMessageHook0(void, CKTranscriptHeaderView, layoutSubviews) { + [self wb$setBackgroundColor:[UIColor clearColor]]; + return MSOldCall(); +} + MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, balloon) { MSOldCall(balloon); [balloon setBackgroundColor:[UIColor clearColor]]; @@ -1505,15 +1810,18 @@ MSInstanceMessageHook1(void, CKMessageCell, addBalloonView, CKBalloonView *, bal MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, color) { MSOldCall([UIColor clearColor]); + [[self contentView] wb$setBackgroundColor:[UIColor clearColor]]; } +// iOS >= 5.0 MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) { if ((self = MSOldCall(style, reuse)) != nil) { [self setBackgroundColor:[UIColor clearColor]]; - [[self contentView] setBackgroundColor:[UIColor clearColor]]; + [[self contentView] wb$setBackgroundColor:[UIColor clearColor]]; } return self; } +// iOS << 5.0 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) { if ((self = MSOldCall(style, reuse)) != nil) { [self setBackgroundColor:[UIColor clearColor]]; @@ -1543,6 +1851,8 @@ MSInstanceMessageHook0(void, CKTranscriptController, loadView) { if (NSString *path = $getTheme$($useScale$([NSArray arrayWithObjects:@"SMSBackground.png", @"SMSBackground.jpg", nil]))) if (UIImage *image = $getImage$(path)) { + SMSBackgrounded_ = true; + UIView *&_transcriptTable(MSHookIvar(self, "_transcriptTable")); UIView *&_transcriptLayer(MSHookIvar(self, "_transcriptLayer")); UIView *table; @@ -1661,7 +1971,7 @@ MSHook(bool, _Z24GetFileNameForThisActionmPcRb, unsigned long a0, char *a1, bool NSString *path([NSString stringWithFormat:@"%@/UISounds/%@", theme, file]); if ([Manager_ fileExistsAtPath:path]) { strcpy(a1, [path UTF8String]); - continue; + break; } } } @@ -1694,7 +2004,7 @@ static void ChangeWallpaper( } #define WBRename(name, sel, imp) \ - _ ## name ## $ ## imp = MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp) + MSHookMessage($ ## name, @selector(sel), &$ ## name ## $ ## imp, &_ ## name ## $ ## imp) template static void msset(Type_ &function, MSImageRef image, const char *name) { @@ -1724,25 +2034,53 @@ MSHook(void *, CGImageReadCreateWithFile, NSString *path, int flag) { [pool release]; return value; } + +MSHook(void *, CGImageSourceCreateWithFile, NSString *path, NSDictionary *options) { + if (Debug_) + NSLog(@"WB:Debug: CGImageSourceCreateWithFile(%@, %@)", path, options); + NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]); + void *value(_CGImageSourceCreateWithFile([path wb$themedPath], options)); + [pool release]; + return value; +} + +MSHook(void *, CGImageSourceCreateWithURL, NSURL *url, NSDictionary *options) { + if (Debug_) + NSLog(@"WB:Debug: CGImageSourceCreateWithURL(%@, %@)", url, options); + NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]); + if ([url isFileURL]) + url = [NSURL fileURLWithPath:[[url path] wb$themedPath]]; + void *value(_CGImageSourceCreateWithURL(url, options)); + [pool release]; + return value; +} // }}} 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]; + //NSLog(@"XXX:drawP(%@ | %@)", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]); + [[WBMarkup sharedMarkup] drawString:self atPoint:point withStyle:style]; +} + +static void NSString$drawInRect$withStyle$(NSString *self, SEL _cmd, CGRect rect, NSString *style) { + WKSetCurrentGraphicsContext(UIGraphicsGetCurrentContext()); + if (style == nil || [style length] == 0) + style = @"font-family: Helvetica; font-size: 12px"; + //NSLog(@"XXX:drawR(%@ | %@)", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "]); + return [[WBMarkup sharedMarkup] drawString:self inRect:rect withStyle:style]; } 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]; + CGSize size([[WBMarkup sharedMarkup] sizeOfString:self withStyle:style forWidth:width]); + //NSLog(@"XXX:size(%@ | %@) = [%g %g]", self, [style stringByReplacingOccurrencesOfString:@"\n" withString:@" "], size.width, size.height); + return size; } 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); WBRename(SBApplicationIcon, icon, icon); @@ -1760,9 +2098,20 @@ static void SBInitialize() { WBRename(SBDockIconListView, setFrame:, setFrame$); MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock); + if (kCFCoreFoundationVersionNumber < 600 || SummerBoard_) + WBRename(SBIconLabel, drawRect:, drawRect$); + else if (kCFCoreFoundationVersionNumber < 700) { + WBRename(SBIconLabel, buildLabelImage, buildLabelImage); + } else { + WBRename(SBIconLabelImageParameters, hash, hash); + WBRename($SBIconView, _labelImageParametersForIcon:location:, _labelImageParametersForIcon$location$); + WBRename($SBIconLabelImage, _drawLabelImageForParameters:, _drawLabelImageForParameters$); + } + WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$); WBRename(SBIconLabel, setInDock:, setInDock$); + WBRename(SBIconList, didMoveToSuperview, didMoveToSuperview); WBRename(SBIconList, setFrame:, setFrame$); WBRename(SBIconModel, cacheImageForIcon:, cacheImageForIcon$); @@ -1791,6 +2140,10 @@ static void SBInitialize() { } MSInitialize { + $objc_setAssociatedObject = reinterpret_cast(dlsym(RTLD_DEFAULT, "objc_setAssociatedObject")); + $objc_getAssociatedObject = reinterpret_cast(dlsym(RTLD_DEFAULT, "objc_getAssociatedObject")); + $objc_removeAssociatedObjects = reinterpret_cast(dlsym(RTLD_DEFAULT, "objc_removeAssociatedObjects")); + NSAutoreleasePool *pool([[NSAutoreleasePool alloc] init]); NSString *identifier([[NSBundle mainBundle] bundleIdentifier]); @@ -1805,8 +2158,13 @@ MSInitialize { if (NSDictionary *settings = [NSDictionary dictionaryWithContentsOfFile:[NSString stringWithFormat:@"/User/Library/Preferences/com.saurik.WinterBoard.plist"]]) { if (NSNumber *value = [settings objectForKey:@"SummerBoard"]) SummerBoard_ = [value boolValue]; + else + SummerBoard_ = true; + if (NSNumber *value = [settings objectForKey:@"Debug"]) Debug_ = [value boolValue]; + if (NSNumber *value = [settings objectForKey:@"RecordUI"]) + UIDebug_ = [value boolValue]; NSArray *themes([settings objectForKey:@"Themes"]); if (themes == nil) @@ -1870,12 +2228,23 @@ MSInitialize { void *(*CGImageReadCreateWithFile)(NSString *, int); msset(CGImageReadCreateWithFile, image, "_CGImageReadCreateWithFile"); MSHookFunction(CGImageReadCreateWithFile, MSHake(CGImageReadCreateWithFile)); + + if (CGImageReadCreateWithFile == NULL) { + void *(*CGImageSourceCreateWithFile)(NSString *, NSDictionary *); + msset(CGImageSourceCreateWithFile, image, "_CGImageSourceCreateWithFile"); + MSHookFunction(CGImageSourceCreateWithFile, MSHake(CGImageSourceCreateWithFile)); + + void *(*CGImageSourceCreateWithURL)(NSURL *, NSDictionary *); + msset(CGImageSourceCreateWithURL, image, "_CGImageSourceCreateWithURL"); + MSHookFunction(CGImageSourceCreateWithURL, MSHake(CGImageSourceCreateWithURL)); + } } // }}} // SpringBoard {{{ if (SpringBoard_) { 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]); + Papered_ = $getTheme$(Wallpapers_) != nil; + Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil; CFNotificationCenterAddObserver( CFNotificationCenterGetDarwinNotifyCenter(), @@ -1896,6 +2265,10 @@ MSInitialize { // }}} // UIKit {{{ if ([NSBundle bundleWithIdentifier:@"com.apple.UIKit"] != nil) { + class_addMethod($NSString, @selector(drawAtPoint:withStyle:), (IMP) &NSString$drawAtPoint$withStyle$, "v20@0:4{CGPoint=ff}8@16"); + class_addMethod($NSString, @selector(drawInRect:withStyle:), (IMP) &NSString$drawInRect$withStyle$, "v28@0:4{CGRect={CGSize=ff}{CGSize=ff}}8@24"); + class_addMethod($NSString, @selector(sizeWithStyle:forWidth:), (IMP) &NSString$sizeWithStyle$forWidth$, "{CGSize=ff}16@0:4@8f12"); + struct nlist nl[6]; memset(nl, 0, sizeof(nl)); nl[0].n_un.n_name = (char *) "__UIApplicationImageWithName"; @@ -1917,8 +2290,13 @@ MSInitialize { } // }}} - if (Debug_ && [Manager_ fileExistsAtPath:@"/tmp/UIImages"]) - UIDebug_ = true; + if (UIDebug_ && ![Manager_ fileExistsAtPath:@"/tmp/UIImages"]) { + NSError *error(nil); + if (![Manager_ createDirectoryAtPath:@"/tmp/UIImages" withIntermediateDirectories:NO attributes:[NSDictionary dictionaryWithObjectsAndKeys: + [NSNumber numberWithShort:0777], NSFilePosixPermissions, + nil] error:&error]) + NSLog(@"WB:Error: cannot create /tmp/UIImages (%@)", error); + } [pool release]; }