I've got a great programming font Deccy that only looks good with font smoothing (anti aliasing) disabled in Xcode. With Xcode 8 the following would do the trick:
defaults write com.apple.dt.Xcode NSFontDefaultScreenFontSubstitutionEnabled -bool YES defaults write com.apple.dt.Xcode AppleAntiAliasingThreshold 24
But this no longer works with Xcode 9.
Would it be possible to disable font smoothing in Xcode 9?
For macOS Catalina (10.15) or below If you are currently on macOS Catalina (10.15) or below, you can remove the text smoothing by: Open System preferences and Appearances. Uncheck the checkbox next to “Use LCD font smoothing when available.”
What is font smoothing? Font smoothing is something that macOS does to make your fonts look slightly bolder. This has the side-effect of messing with carefully designed character shapes produced by font creators, and makes text more blurry.
Here's a screenshot of my Xcode 9 with Deccy at 13pt:
I believe the above is what you want. Here's stock Xcode displaying the same file:
I probed deep for a noninvasive way to accomplish this, and failed. As far as I can tell, the text rendering path in Xcode 9 very deliberately turns on font smoothing.
Before going any further, please file a feature request with Apple. It only takes a few minutes, and it's your best hope for an answer that that can be discussed in front of those with sound security instincts and strained cardiovasculature:
https://bugreport.apple.com/
I wrote an Xcode plugin. You might have heard that Xcode 9 uses code signing restrictions to forbid the loading of plugins. This is true, but a few mavericks press on, and tonight we ride with them.
There is a tool, update_xcode_plugins. You can use it to strip the code signature from your copy of Xcode, and with it the bundle-loading restriction:
$ gem install update_xcode_plugins $ update_xcode_plugins --unsign
If you change your mind, you can do this to revert to (a backup copy, I think?) of signed Xcode:
$ update_xcode_plugins --restore
There is another tool, Alcatraz. It's a plugin manager for Xcode. I chose to install it because it provides a plugin which provides a project template for plugins. I followed these instructions to install Alcatraz, which boil down to this:
$ git clone https://github.com/alcatraz/Alcatraz.git $ cd Alcatraz $ xcodebuild
I launched Xcode, clicked through the dialog warning me about the new plugin, and then used the newly-added Window > Package Manager to install the "Xcode Plugin" template.
I made a project with this template.
As I write this, the "Xcode Plugin" template hasn't been updated to support Xcode 9. No worries. I ran this command to grab Xcode 9's compatibility UUID:
$ defaults read /Applications/Xcode.app/Contents/Info DVTPlugInCompatibilityUUID
I visited my new project's Info.plist and added that UUID to the DVTPlugInCompatibilityUUIDs
array.
Then, I linked SourceEditor.framework
into my project. That was a two-step process:
Visit the target's Build Settings. Add this to Framework Search Paths:
/Applications/Xcode.app/Contents/SharedFrameworks/
Visit the target's Build Phases. Add a new "Link Binary With Libraries" phase. Hit the plus. Navigate to the directory above (you can just press the / key and then paste the path in) and choose SourceEditor.framework
. It should appear in the list. The project should still build.
Then, I made my plugin's .mm
file look like this (I deleted the .h
file, it's unneeded for this PoC):
#import <AppKit/AppKit.h> #include <dlfcn.h> extern void CGContextSetAllowsFontAntialiasing(CGContextRef, BOOL); static void hooked_sourceEditorSetFontSmoothingStyle(CGContextRef ctx) { CGContextSetAllowsFontAntialiasing(ctx, NO); } @interface NoAA : NSObject @end @implementation NoAA + (void)pluginDidLoad:(NSBundle *)plugin { NSArray *allowedLoaders = [plugin objectForInfoDictionaryKey:@"me.delisa.XcodePluginBase.AllowedLoaders"]; if (![allowedLoaders containsObject:[[NSBundle mainBundle] bundleIdentifier]]) return; Class cls = NSClassFromString(@"SourceEditorScrollView"); NSBundle* bundle = [NSBundle bundleForClass:cls]; void *handle = dlopen(bundle.executablePath.fileSystemRepresentation, RTLD_NOW); if (!handle) return; uint8_t* set_font_smoothing_fn = dlsym(handle, "sourceEditorSetFontSmoothingStyle"); if (!set_font_smoothing_fn) goto fin; void* set_font_smoothing_fn_page = (void*)((long)set_font_smoothing_fn & -PAGE_SIZE); if (mprotect(set_font_smoothing_fn_page, PAGE_SIZE, PROT_READ | PROT_WRITE | PROT_EXEC)) goto fin; set_font_smoothing_fn[0] = 0xe9; // jmp uint32_t* jmp_arg = (uint32_t*)(set_font_smoothing_fn + 1); *jmp_arg = (uint32_t)((long)hooked_sourceEditorSetFontSmoothingStyle - (long)(jmp_arg + 1)); mprotect(set_font_smoothing_fn_page, PAGE_SIZE, PROT_READ | PROT_EXEC); fin: dlclose(handle); } @end
…I think the goto
s add character. Basically, it just defines a function that takes a CGContextRef
and turns off text antialiasing for it. Then, it overwrites the beginning of a function inside the SourceEditor framework which ordinarily configures antialiasing settings — don't need that anymore — to jump to our function instead. It does all of this in an incredibly unsafe way, so if something goes wrong, Xcode may politely crash.
Build and run the project, which automatically installs the plugin. Accept the addition of your plugin, and that's that.
If anything here doesn't work because I messed up, let me know. I'm not planning to roll this into an Alcatraz plugin myself, but you or anyone else should free to do so with credit (after filing a feature request with Apple).
Happy hacking!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With