]> git.saurik.com Git - winterboard.git/blobdiff - Library.mm
Finish re-integrating WinterBoard label code.
[winterboard.git] / Library.mm
index a872c5ce841761c0b68519906e7483121ae01747..918978aea13f4c2ed248df6f281142abd952ac80 100644 (file)
@@ -122,6 +122,7 @@ MSMetaClassHook(UIImage)
 MSClassHook(UINavigationBar)
 MSClassHook(UIToolbar)
 
+MSClassHook(CKBalloonView)
 MSClassHook(CKMessageCell)
 MSClassHook(CKTimestampView)
 MSClassHook(CKTranscriptCell)
@@ -241,7 +242,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];
@@ -275,9 +276,10 @@ static NSArray *$useScale$(NSArray *files, bool use = true) {
             [scaled addObject:[NSString stringWithFormat:@"%@~iphone.%@", base, extension]];
             [scaled addObject:file];
 
-            NSString *rest([base substringWithRange:NSMakeRange(0, [base length] - 3)]);
+            // 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:@"%@~iphone.%@", rest, extension]];
-            [scaled addObject:[rest stringByAppendingPathExtension:extension]];
+            [scaled addObject:[rest stringByAppendingPathExtension:extension]];*/
         } else {
             // XXX: this code isn't really complete
 
@@ -292,8 +294,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<id>(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<id>(path) == [NSNull null] ? nil : path;
+    }
 
     if (Debug_)
         NSLog(@"WB:Debug: %@", [files description]);
@@ -310,7 +317,10 @@ static NSString *$getTheme$(NSArray *files, NSArray *themes = Themes_) {
     path = nil;
   set:
 
-    [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:files];
+    @synchronized (Themed_) {
+        [Themed_ setObject:(path == nil ? [NSNull null] : reinterpret_cast<id>(path)) forKey:key];
+    }
+
     return path;
 }
 // }}}
@@ -321,8 +331,12 @@ 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 (ui)
         [names addObject:[NSString stringWithFormat:@"UIImages/%@", file]];
 
@@ -342,6 +356,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;
 
@@ -660,6 +676,35 @@ 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_;
@@ -667,44 +712,84 @@ static struct WBStringDrawingState {
     NSString *info_;
 } *stringDrawingState_;
 
-MSInstanceMessageHook4(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode, CGPoint, point, float, width, UIFont *, font, int, mode) {
+MSInstanceMessageHook6(CGSize, NSString, drawAtPoint,forWidth,withFont,lineBreakMode,letterSpacing,includeEmoji, CGPoint, point, float, width, UIFont *, font, UILineBreakMode, mode, float, spacing, BOOL, emoji) {
     WBStringDrawingState *state(stringDrawingState_);
     if (state == NULL)
-        return MSOldCall(point, width, font, mode);
+        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);
+        return MSOldCall(point, width, font, mode, spacing, emoji);
 
     NSString *info([Info_ objectForKey:state->info_]);
     if (info == nil)
-        return MSOldCall(point, width, font, mode);
+        return MSOldCall(point, width, font, mode, spacing, emoji);
 
     NSString *base(state->base_ ?: @"");
-    [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]];
+    NSString *extra([NSString stringWithFormat:@"letter-spacing: %gpx", spacing]);
+    [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], extra, base, info]];
     return CGSizeZero;
 }
 
-MSInstanceMessageHook2(CGSize, NSString, drawAtPoint,withFont, CGPoint, point, UIFont *, font) {
+MSInstanceMessageHook7(CGSize, NSString, _drawInRect,withFont,lineBreakMode,alignment,lineSpacing,includeEmoji,truncationRect, CGRect, rect, UIFont *, font, UILineBreakMode, mode, UITextAlignment, alignment, float, spacing, BOOL, emoji, CGRect, truncation) {
     WBStringDrawingState *state(stringDrawingState_);
     if (state == NULL)
-        return MSOldCall(point, font);
+        return MSOldCall(rect, font, mode, alignment, spacing, emoji, truncation);
 
     if (--state->count_ == 0)
         stringDrawingState_ = state->next_;
     if (state->info_ == nil)
-        return MSOldCall(point, font);
+        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 *textAlign;
+    switch (alignment) {
+        default:
+        case UITextAlignmentLeft:
+            textAlign = @"left";
+            break;
+        case UITextAlignmentCenter:
+            textAlign = @"center";
+            break;
+        case UITextAlignmentRight:
+            textAlign = @"right";
+            break;
+    }
 
     NSString *base(state->base_ ?: @"");
-    [self drawAtPoint:point withStyle:[NSString stringWithFormat:@"%@;%@;%@", [font markupDescription], base, info]];
+    NSString *extra([NSString stringWithFormat:@"text-align: %@", textAlign]);
+
+    if (true)
+        $drawLabel$(self, rect, [NSString stringWithFormat:@"%@;%@", [font markupDescription], base], info);
+    else
+        [self drawInRect:rect withStyle:[NSString stringWithFormat:@"%@;%@;%@;%@", [font markupDescription], extra, base, info]];
+
     return CGSizeZero;
 }
 
+MSInstanceMessageHook4(CGSize, NSString, sizeWithFont,forWidth,lineBreakMode,letterSpacing, UIFont *, font, float, width, UILineBreakMode, mode, float, 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], extra, base, info] forWidth:width];
+}
+
 MSInstanceMessageHook1(CGSize, NSString, sizeWithFont, UIFont *, font) {
     WBStringDrawingState *state(stringDrawingState_);
     if (state == NULL)
@@ -867,6 +952,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_;
@@ -1156,7 +1242,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<BOOL>(view_, "_mode"));;
 
@@ -1203,7 +1289,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; "
@@ -1486,9 +1572,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;
@@ -1511,35 +1595,39 @@ 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<unsigned>(self, "_inDock") & 0x2) != 0);
 
-        style = [style stringByAppendingString:[NSString stringWithFormat:@"letter-spacing: -%f; ", spacing]];
-    }
+    WBStringDrawingState labelState = {NULL, 0, [NSString stringWithFormat:@""
+        "color: %@;"
+    ,
+        (docked || !SummerBoard_ ? @"white" : @"#b3b3b3")
+    ], docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle"};
 
-    if (ellipsis)
-        label = [label stringByAppendingString:@"..."];
+    stringDrawingState_ = &labelState;
 
-    if (NSString *custom = [Info_ objectForKey:(docked ? @"DockedIconLabelStyle" : @"UndockedIconLabelStyle")])
-        style = [style stringByAppendingString:custom];
+    CGImageRef image(MSOldCall());
 
-    CGSize size = [label sizeWithStyle:style forWidth:bounds.size.width];
-    [label drawAtPoint:CGPointMake((bounds.size.width - size.width) / 2, 0) withStyle:style];
+    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();
@@ -1555,6 +1643,7 @@ MSInstanceMessageHook1(void, CKTranscriptCell, setBackgroundColor, UIColor *, co
     [[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]];
@@ -1562,6 +1651,7 @@ MSInstanceMessageHook2(id, CKTranscriptCell, initWithStyle,reuseIdentifier, int,
     } return self;
 }
 
+// iOS << 5.0
 MSInstanceMessageHook2(id, CKMessageCell, initWithStyle,reuseIdentifier, int, style, NSString *, reuse) {
     if ((self = MSOldCall(style, reuse)) != nil) {
         [self setBackgroundColor:[UIColor clearColor]];
@@ -1591,6 +1681,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<UIView *>(self, "_transcriptTable"));
             UIView *&_transcriptLayer(MSHookIvar<UIView *>(self, "_transcriptLayer"));
             UIView *table;
@@ -1781,6 +1873,13 @@ static void NSString$drawAtPoint$withStyle$(NSString *self, SEL _cmd, CGPoint po
     return [[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";
+    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";
@@ -1789,6 +1888,7 @@ static CGSize NSString$sizeWithStyle$forWidth$(NSString *self, SEL _cmd, NSStrin
 
 static void SBInitialize() {
     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");
 
     if (SummerBoard_) {
@@ -1808,6 +1908,11 @@ static void SBInitialize() {
     WBRename(SBDockIconListView, setFrame:, setFrame$);
     MSHookMessage(object_getClass($SBDockIconListView), @selector(shouldShowNewDock), &$SBDockIconListView$shouldShowNewDock, &_SBDockIconListView$shouldShowNewDock);
 
+    if (kCFCoreFoundationVersionNumber < 600)
+        WBRename(SBIconLabel, drawRect:, drawRect$);
+    else
+        WBRename(SBIconLabel, buildLabelImage, buildLabelImage);
+
     WBRename(SBIconLabel, initWithSize:label:, initWithSize$label$);
     WBRename(SBIconLabel, setInDock:, setInDock$);
 
@@ -1926,7 +2031,7 @@ MSInitialize {
     if (SpringBoard_) {
         Wallpapers_ = [[NSArray arrayWithObjects:@"Wallpaper.mp4", @"Wallpaper@2x.png", @"Wallpaper@2x.jpg", @"Wallpaper.png", @"Wallpaper.jpg", @"Wallpaper.html", nil] retain];
         Papered_ = $getTheme$(Wallpapers_) != nil;
-        Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]);
+        Docked_ = $getTheme$([NSArray arrayWithObjects:@"Dock.png", nil]) != nil;
 
         CFNotificationCenterAddObserver(
             CFNotificationCenterGetDarwinNotifyCenter(),