forked from tjw/XcodeSelectionColorFix
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.m
More file actions
132 lines (110 loc) · 5.18 KB
/
Copy pathmain.m
File metadata and controls
132 lines (110 loc) · 5.18 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
#import <Cocoa/Cocoa.h>
#import "OBMethodReplacement.h"
#import <libkern/OSAtomic.h>
#import <crt_externs.h>
@interface com_omnigroup_XcodeSelectionColorFix : NSObject
@end
@implementation com_omnigroup_XcodeSelectionColorFix
static NSColor *(*original_secondarySelectedControlColor)(id self, SEL _cmd) = NULL;
static void (*original_drawBackgroundForGlyphRange)(id self, SEL _cmd, NSRange glyphsToShow, NSPoint origin) = NULL;
static int32_t drawBackgroundForGlyphRangeNesting = 0;
static Class DVTLayoutManager = Nil;
static Class DVTFontAndColorTheme = Nil;
static Class DVTSourceTextView = Nil;
static Class IDEConsoleTextView = Nil;
#define REQUIRE_CLASS(x) \
do { \
x = NSClassFromString((id)CFSTR(#x)); \
if (!x) { \
NSLog(@"%s: Unable to find class \"%s\"!", __PRETTY_FUNCTION__, #x); \
return; \
} \
} while (0)
#define REQUIRE_CLASS_METHOD(cls, name) \
do { \
if (![cls respondsToSelector:@selector(name)]) { \
NSLog(@"%s: \"%s\" doesn't respond to +%s.", __PRETTY_FUNCTION__, #cls, #name); \
return; \
} \
} while (0)
#define REQUIRE_INSTANCE_METHOD(cls, name) \
do { \
if (![cls instancesRespondToSelector:@selector(name)]) { \
NSLog(@"%s: Instances of \"%s\" don't respond to -%s.", __PRETTY_FUNCTION__, #cls, #name); \
return; \
} \
} while (0)
+ (void)load;
{
// xcodebuild will load Xcode plugins too, but doesn't have the text related classes. Don't emit warnings if running xcodebuild.
char **progname = _NSGetProgname();
if (progname && *progname && strstr(*progname, "xcodebuild") != NULL)
return;
// Could also check the superclasses of these, but that seems like overkill
REQUIRE_CLASS(DVTLayoutManager);
REQUIRE_CLASS(DVTFontAndColorTheme);
REQUIRE_CLASS_METHOD(DVTFontAndColorTheme, currentTheme);
REQUIRE_INSTANCE_METHOD(DVTFontAndColorTheme, sourceTextSelectionColor);
REQUIRE_INSTANCE_METHOD(DVTFontAndColorTheme, consoleTextSelectionColor);
REQUIRE_CLASS(DVTSourceTextView);
REQUIRE_CLASS(IDEConsoleTextView);
original_secondarySelectedControlColor = (typeof(original_secondarySelectedControlColor))OBReplaceMethodImplementationWithSelectorOnClass(object_getClass([NSColor class]), @selector(secondarySelectedControlColor), self, @selector(replacement_secondarySelectedControlColor));
if (!original_secondarySelectedControlColor) {
NSLog(@"Unable to replace method.");
return;
}
original_drawBackgroundForGlyphRange = (typeof(original_drawBackgroundForGlyphRange))OBReplaceMethodImplementationWithSelectorOnClass(DVTLayoutManager, @selector(drawBackgroundForGlyphRange:atPoint:), self, @selector(replacement_drawBackgroundForGlyphRange:atPoint:));
if (!original_drawBackgroundForGlyphRange) {
NSLog(@"Unable to replace method.");
return;
}
// Install light-mode cursors for the source and debug console
if (!OBReplaceMethodImplementationWithSelectorOnClass(DVTSourceTextView, @selector(_mouseInside:), self, @selector(_mouseInside:))) {
NSLog(@"Unable to replace method.");
return;
}
if (!OBReplaceMethodImplementationWithSelectorOnClass(IDEConsoleTextView, @selector(_mouseInside:), self, @selector(_mouseInside:))) {
NSLog(@"Unable to replace method.");
return;
}
}
- (NSColor *)replacement_secondarySelectedControlColor;
{
if (drawBackgroundForGlyphRangeNesting == 0)
return original_secondarySelectedControlColor(self, _cmd);
// Return a color interpolated between the user's background color and selection color.
id theme = [DVTFontAndColorTheme performSelector:@selector(currentTheme)];
NSColor *color0 = [[theme performSelector:@selector(sourceTextSelectionColor)] colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
NSColor *color1 = [[theme performSelector:@selector(sourceTextBackgroundColor)] colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
return [color0 blendedColorWithFraction:0.5 ofColor:color1];
}
- (void)replacement_drawBackgroundForGlyphRange:(NSRange)glyphsToShow atPoint:(NSPoint)origin;
{
OSAtomicIncrement32(&drawBackgroundForGlyphRangeNesting);
@try {
original_drawBackgroundForGlyphRange(self, _cmd, glyphsToShow, origin);
} @finally {
OSAtomicDecrement32(&drawBackgroundForGlyphRangeNesting);
}
}
// Normally the IBeamCursor is set by this hitting a implementation on NSTextView. I'm hooking it on DVTSourceTextView for now, but it might need to be more tightly tuned.
- (void)_mouseInside:(NSEvent *)event;
{
static NSCursor *cursor = nil;
if (!cursor) {
NSString *imagePath = [[NSBundle bundleWithIdentifier:@"com.omnigroup.XcodeSelectionColorFix"] pathForImageResource:@"cursor"];
if (!imagePath) {
NSLog(@"No cursor image found!");
} else {
NSImage *image = [[NSImage alloc] initWithContentsOfFile:imagePath];
if (!image)
NSLog(@"Unable to load cursor image");
else
cursor = [[NSCursor alloc] initWithImage:image hotSpot:[[NSCursor IBeamCursor] hotSpot]];
}
if (!cursor)
cursor = [[NSCursor IBeamCursor] retain];
}
[cursor set];
}
@end