Revision: 14424
http://sourceforge.net/p/skim-app/code/14424
Author: hofman
Date: 2024-08-15 23:40:17 +0000 (Thu, 15 Aug 2024)
Log Message:
-----------
observe universalaccess defaults to reset custom cursors instead of checking it
for every custom cursor getter
Modified Paths:
--------------
trunk/NSCursor_SKExtensions.m
Modified: trunk/NSCursor_SKExtensions.m
===================================================================
--- trunk/NSCursor_SKExtensions.m 2024-08-15 21:31:03 UTC (rev 14423)
+++ trunk/NSCursor_SKExtensions.m 2024-08-15 23:40:17 UTC (rev 14424)
@@ -45,6 +45,8 @@
#import "NSShadow_SKExtensions.h"
#import "NSBezierPath_SKExtensions.h"
+static char SKUniversalAccessDefaultsObservationContext;
+
static inline void hideLaserPointer(void);
@interface NSCursor (SKPrivateDeclarations)
@@ -52,11 +54,28 @@
+ (id)_windowResizeNorthEastSouthWestCursor;
@end
+#pragma mark -
+
@interface SKLaserPointerCursor : NSCursor
@end
#pragma mark -
+@interface SKCustomCursors : NSObject {
+ NSUserDefaults *universalaccessDefaults;
+ NSMutableDictionary *customCursors;
+}
+
+@property(class, nonatomic, readonly) SKCustomCursors *sharedCustomCursors;
+
+@property (nonatomic, readonly) NSUserDefaults *universalaccessDefaults;
+
+- (NSCursor *)cursorWithName:(NSString *)name;
+
+@end
+
+#pragma mark -
+
@implementation NSCursor (SKExtensions)
static void (*original_set)(id, SEL) = NULL;
@@ -77,43 +96,197 @@
original_hide = (void(*)(id,
SEL))SKReplaceClassMethodImplementationFromSelector(self, @selector(hide),
@selector(replacement_hide));
}
-static NSUserDefaults *universalaccessDefaults() {
- static NSUserDefaults *universalaccessDefaults = nil;
- if (universalaccessDefaults == nil)
- universalaccessDefaults = [[NSUserDefaults alloc]
initWithSuiteName:@"com.apple.universalaccess"];
- return universalaccessDefaults;
++ (NSCursor *)zoomInCursor {
+ return [[SKCustomCursors sharedCustomCursors]
cursorWithName:@"zoomInCursor"];
}
-static NSDictionary *currentCursorColors() {
- if (@available(macOS 12.0, *)) {
- if ([universalaccessDefaults() boolForKey:@"cursorIsCustomized"]) {
- NSDictionary *cursorOutline = [universalaccessDefaults()
dictionaryForKey:@"cursorOutline"];
- NSDictionary *cursorFill = [universalaccessDefaults()
dictionaryForKey:@"cursorFill"];
- if ([cursorOutline count] == 4 && [cursorFill count] == 4)
- return @{@"cursorOutline":cursorOutline,
@"cursorFill":cursorFill};
- }
++ (NSCursor *)zoomOutCursor {
+ return [[SKCustomCursors sharedCustomCursors]
cursorWithName:@"zoomOutCursor"];
+}
+
++ (NSCursor *)resizeDiagonal45Cursor {
+ if ([self
respondsToSelector:@selector(_windowResizeNorthEastSouthWestCursor)]) {
+ return [NSCursor _windowResizeNorthEastSouthWestCursor];
+ } else {
+ return [[SKCustomCursors sharedCustomCursors]
cursorWithName:@"resizeDiagonal45Cursor"];
}
- return @{};
}
-+ (NSCursor *)customCursorWithName:(NSString *)name {
- static NSMutableDictionary *customCursors = nil;
- static NSDictionary *cursorColors = nil;
++ (NSCursor *)resizeDiagonal135Cursor {
+ if ([self
respondsToSelector:@selector(_windowResizeNorthWestSouthEastCursor)]) {
+ return [NSCursor _windowResizeNorthWestSouthEastCursor];
+ } else {
+ return [[SKCustomCursors sharedCustomCursors]
cursorWithName:@"resizeDiagonal135Cursor"];
+ }
+}
+
++ (NSCursor *)cameraCursor {
+ return [[SKCustomCursors sharedCustomCursors]
cursorWithName:@"cameraCursor"];
+}
+
++ (NSCursor *)openHandBarCursor {
+ return [[SKCustomCursors sharedCustomCursors]
cursorWithName:@"openHandBarCursor"];
+}
+
++ (NSCursor *)closedHandBarCursor {
+ return [[SKCustomCursors sharedCustomCursors]
cursorWithName:@"closedHandBarCursor"];
+}
+
++ (NSCursor *)textNoteCursor {
+ return [[SKCustomCursors sharedCustomCursors]
cursorWithName:@"textNoteCursor"];
+}
+
++ (NSCursor *)anchoredNoteCursor {
+ return [[SKCustomCursors sharedCustomCursors]
cursorWithName:@"anchoredNoteCursor"];
+}
+
++ (NSCursor *)circleNoteCursor {
+ return [[SKCustomCursors sharedCustomCursors]
cursorWithName:@"circleNoteCursor"];
+}
+
++ (NSCursor *)squareNoteCursor {
+ return [[SKCustomCursors sharedCustomCursors]
cursorWithName:@"squareNoteCursor"];
+}
+
++ (NSCursor *)highlightNoteCursor {
+ return [[SKCustomCursors sharedCustomCursors]
cursorWithName:@"highlightNoteCursor"];
+}
+
++ (NSCursor *)underlineNoteCursor {
+ return [[SKCustomCursors sharedCustomCursors]
cursorWithName:@"underlineNoteCursor"];
+}
+
++ (NSCursor *)strikeOutNoteCursor {
+ return [[SKCustomCursors sharedCustomCursors]
cursorWithName:@"strikeOutNoteCursor"];
+}
+
++ (NSCursor *)lineNoteCursor {
+ return [[SKCustomCursors sharedCustomCursors]
cursorWithName:@"lineNoteCursor"];
+}
+
++ (NSCursor *)inkNoteCursor {
+ return [[SKCustomCursors sharedCustomCursors]
cursorWithName:@"inkNoteCursor"];
+}
+
++ (NSCursor *)emptyCursor {
+ static NSCursor *emptyCursor = nil;
+ if (nil == emptyCursor) {
+ NSImage *cursorImage = [[NSImage alloc] initWithSize:NSMakeSize(16.0,
16.0)];
+ emptyCursor = [[NSCursor alloc] initWithImage:cursorImage
hotSpot:NSMakePoint(8.0, 8.0)];
+ }
+ return emptyCursor;
+}
+
++ (NSCursor *)laserPointerCursorWithColor:(NSInteger)color {
+ static NSPointerArray *laserPointerCursors = nil;
+ if (laserPointerCursors == nil) {
+ laserPointerCursors = [NSPointerArray strongObjectsPointerArray];
+ [laserPointerCursors setCount:7];
+ }
+ NSCursor *cursor = (__bridge id)[laserPointerCursors pointerAtIndex:color
% 7];
+ if (nil == cursor) {
+ NSImage *cursorImage = [NSImage laserPointerImageWithColor:color % 7];
+ cursor = [[NSCursor alloc] initWithImage:cursorImage
hotSpot:NSMakePoint(0.5 * [cursorImage size].width, 0.5 * [cursorImage
size].height)];
+ [laserPointerCursors replacePointerAtIndex:color % 7
withPointer:(__bridge void *)cursor];
+ }
+ return cursor;
+}
+
++ (NSCursor *)safeLaserPointerCursorWithColor:(NSInteger)color {
+ static NSPointerArray *laserPointerCursors = nil;
+ if (laserPointerCursors == nil) {
+ laserPointerCursors = [NSPointerArray strongObjectsPointerArray];
+ [laserPointerCursors setCount:7];
+ }
+ NSCursor *cursor = (__bridge id)[laserPointerCursors pointerAtIndex:color
% 7];
+ if (nil == cursor) {
+ NSImage *cursorImage = [NSImage laserPointerImageWithColor:color % 7];
+ cursor = [[SKLaserPointerCursor alloc] initWithImage:cursorImage
hotSpot:NSMakePoint(0.5 * [cursorImage size].width, 0.5 * [cursorImage
size].height)];
+ [laserPointerCursors replacePointerAtIndex:color % 7
withPointer:(__bridge void *)cursor];
+ }
+ return cursor;
+}
+
+@end
+
+#pragma mark -
+
+static NSWindow *laserPointerWindow = nil;
+
+static inline void hideLaserPointer(void) {
+ if (laserPointerWindow) {
+ [laserPointerWindow close];
+ laserPointerWindow = nil;
+ }
+}
+
+@implementation SKLaserPointerCursor
+
+- (void)set {
+ if (original_set)
+ original_set([NSCursor emptyCursor], _cmd);
+ else
+ [[NSCursor emptyCursor] set];
- NSDictionary *currentColors = currentCursorColors();
-
- if ([currentColors isEqualToDictionary:cursorColors] == NO) {
- cursorColors = currentColors;
-
+ NSPoint p = [NSEvent mouseLocation];
+ p = NSMakePoint(round(p.x), round(p.y));
+ if (laserPointerWindow) {
+ [[[[laserPointerWindow contentView] subviews] firstObject]
setImage:[self image]];
+ [laserPointerWindow setFrame:SKRectFromCenterAndSize(p,
[laserPointerWindow frame].size) display:YES];
+ } else {
+ NSImage *image = [self image];
+ CGFloat size = [[[SKCustomCursors sharedCustomCursors]
universalaccessDefaults] doubleForKey:@"mouseDriverCursorSize"];
+ CGFloat s = 2.0 * round(0.5 * (size > 0.0 ? size : 1.0) * [image
size].width);
+ laserPointerWindow = [[SKAnimatedBorderlessWindow alloc]
initWithContentRect:SKRectFromCenterAndSquareSize(p, s)];
+ [laserPointerWindow setLevel:(NSWindowLevel)kCGCursorWindowLevel];
+ [laserPointerWindow addImageViewWithImage:image];
+ [laserPointerWindow setHidesOnDeactivate:YES];
+ [laserPointerWindow orderFrontRegardless];
+ }
+}
+
+@end
+
+#pragma mark -
+
+@implementation SKCustomCursors
+
+@dynamic universalaccessDefaults;
+
++ (SKCustomCursors *)sharedCustomCursors {
+ static SKCustomCursors *sharedCustomCursors = nil;
+ if (sharedCustomCursors == nil)
+ sharedCustomCursors = [[self alloc] init];
+ return sharedCustomCursors;
+}
+
+- (NSUserDefaults *)universalaccessDefaults {
+ if (universalaccessDefaults == nil) {
+ universalaccessDefaults = [[NSUserDefaults alloc]
initWithSuiteName:@"com.apple.universalaccess"];
+ [universalaccessDefaults addObserver:self
forKeyPath:@"cursorIsCustomized" options:0
context:&SKUniversalAccessDefaultsObservationContext];
+ [universalaccessDefaults addObserver:self forKeyPath:@"cursorOutline"
options:0 context:&SKUniversalAccessDefaultsObservationContext];
+ [universalaccessDefaults addObserver:self forKeyPath:@"cursorFill"
options:0 context:&SKUniversalAccessDefaultsObservationContext];
+ }
+ return universalaccessDefaults;
+}
+
+- (NSCursor *)cursorWithName:(NSString *)name {
+ if (customCursors == nil) {
customCursors = [NSMutableDictionary dictionary];
+ BOOL isCustomized = NO;
NSColor *cursorOutline = [NSColor whiteColor];
NSColor *cursorFill = [NSColor blackColor];
- if ([cursorColors count] == 2) {
- NSDictionary *color = [cursorColors objectForKey:@"cursorOutline"];
- cursorOutline = [NSColor colorWithSRGBRed:[[color
objectForKey:@"red"] doubleValue] green:[[color objectForKey:@"green"]
doubleValue] blue:[[color objectForKey:@"blue"] doubleValue] alpha:[[color
objectForKey:@"alpha"] doubleValue]] ?: cursorOutline;
- color = [cursorColors objectForKey:@"cursorFill"];
- cursorFill = [NSColor colorWithSRGBRed:[[color
objectForKey:@"red"] doubleValue] green:[[color objectForKey:@"green"]
doubleValue] blue:[[color objectForKey:@"blue"] doubleValue] alpha:[[color
objectForKey:@"alpha"] doubleValue]] ?: cursorFill;
+ if (@available(macOS 12.0, *)) {
+ if ([[self universalaccessDefaults]
boolForKey:@"cursorIsCustomized"]) {
+ isCustomized = YES;
+ NSDictionary *outlineDict = [[self universalaccessDefaults]
dictionaryForKey:@"cursorOutline"];
+ NSDictionary *fillDict = [[self universalaccessDefaults]
dictionaryForKey:@"cursorfill"];
+ if ([outlineDict count] == 4 && [fillDict count] == 4) {
+ cursorOutline = [NSColor colorWithSRGBRed:[[outlineDict
objectForKey:@"red"] doubleValue] green:[[outlineDict objectForKey:@"green"]
doubleValue] blue:[[outlineDict objectForKey:@"blue"] doubleValue]
alpha:[[outlineDict objectForKey:@"alpha"] doubleValue]] ?: cursorOutline;
+ cursorFill = [NSColor colorWithSRGBRed:[[fillDict
objectForKey:@"red"] doubleValue] green:[[fillDict objectForKey:@"green"]
doubleValue] blue:[[fillDict objectForKey:@"blue"] doubleValue]
alpha:[[fillDict objectForKey:@"alpha"] doubleValue]] ?: cursorFill;
+ }
+ }
}
NSImage *image;
@@ -344,7 +517,7 @@
[NSBezierPath fillRect:NSMakeRect(2.0, 14.0, 28.0, 4.0)];
NSBezierPath *path = [NSBezierPath openHandBezierPath];
[NSGraphicsContext saveGraphicsState];
- [([cursorColors count] ? cursorFill : cursorOutline) setFill];
+ [(isCustomized ? cursorFill : cursorOutline) setFill];
[NSShadow setShadowWithWhite:0.0 alpha:0.5 blurRadius:1.0
yOffset:-1.4];
[path fill];
[NSGraphicsContext restoreGraphicsState];
@@ -354,7 +527,7 @@
[path lineToPoint:NSMakePoint(17.5348, 14.727)];
[path moveToPoint:NSMakePoint(15.5547, 14.6953)];
[path lineToPoint:NSMakePoint(15.5758, 11.2691)];
- [([cursorColors count] ? cursorOutline : cursorFill) setStroke];
+ [(isCustomized ? cursorOutline : cursorFill) setStroke];
[path setLineWidth:0.75];
[path stroke];
}];
@@ -371,7 +544,7 @@
[NSBezierPath fillRect:NSMakeRect(2.0, 14.0, 28.0, 4.0)];
NSBezierPath *path = [NSBezierPath closedHandBezierPath];
[NSGraphicsContext saveGraphicsState];
- [([cursorColors count] ? cursorFill : cursorOutline) setFill];
+ [(isCustomized ? cursorFill : cursorOutline) setFill];
[NSShadow setShadowWithWhite:0.0 alpha:0.5 blurRadius:1.0
yOffset:-1.4];
[path fill];
[NSGraphicsContext restoreGraphicsState];
@@ -381,7 +554,7 @@
[path lineToPoint:NSMakePoint(17.5348, 14.727)];
[path moveToPoint:NSMakePoint(15.5547, 14.6953)];
[path lineToPoint:NSMakePoint(15.5758, 11.2691)];
- [([cursorColors count] ? cursorOutline : cursorFill) setStroke];
+ [(isCustomized ? cursorOutline : cursorFill) setStroke];
[path setLineWidth:0.75];
[path stroke];
}];
@@ -399,7 +572,7 @@
[customCursors setObject:cursor forKey:@"anchoredNoteCursor"];
image = [NSImage cursorCircleNoteImageWithOutlineColor:cursorOutline
fillColor:cursorFill];
- cursor = [[NSCursor alloc] initWithImage:image hotSpot:[[self
arrowCursor] hotSpot]];
+ cursor = [[NSCursor alloc] initWithImage:image hotSpot:hotspot];
[customCursors setObject:cursor forKey:@"circleNoteCursor"];
image = [NSImage cursorSquareNoteImageWithOutlineColor:cursorOutline
fillColor:cursorFill];
@@ -430,153 +603,12 @@
return [customCursors objectForKey:name];
}
-+ (NSCursor *)zoomInCursor {
- return [self customCursorWithName:@"zoomInCursor"];
-}
-
-+ (NSCursor *)zoomOutCursor {
- return [self customCursorWithName:@"zoomOutCursor"];
-}
-
-+ (NSCursor *)resizeDiagonal45Cursor {
- if ([self
respondsToSelector:@selector(_windowResizeNorthEastSouthWestCursor)]) {
- return [NSCursor _windowResizeNorthEastSouthWestCursor];
+- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void *)context {
+ if (context == &SKUniversalAccessDefaultsObservationContext) {
+ customCursors = nil;
} else {
- return [self customCursorWithName:@"resizeDiagonal45Cursor"];
+ [super observeValueForKeyPath:keyPath ofObject:object change:change
context:context];
}
}
-+ (NSCursor *)resizeDiagonal135Cursor {
- if ([self
respondsToSelector:@selector(_windowResizeNorthWestSouthEastCursor)]) {
- return [NSCursor _windowResizeNorthWestSouthEastCursor];
- } else {
- return [self customCursorWithName:@"resizeDiagonal135Cursor"];
- }
-}
-
-+ (NSCursor *)cameraCursor {
- return [self customCursorWithName:@"cameraCursor"];
-}
-
-+ (NSCursor *)openHandBarCursor {
- return [self customCursorWithName:@"openHandBarCursor"];
-}
-
-+ (NSCursor *)closedHandBarCursor {
- return [self customCursorWithName:@"closedHandBarCursor"];
-}
-
-+ (NSCursor *)textNoteCursor {
- return [self customCursorWithName:@"textNoteCursor"];
-}
-
-+ (NSCursor *)anchoredNoteCursor {
- return [self customCursorWithName:@"anchoredNoteCursor"];
-}
-
-+ (NSCursor *)circleNoteCursor {
- return [self customCursorWithName:@"circleNoteCursor"];
-}
-
-+ (NSCursor *)squareNoteCursor {
- return [self customCursorWithName:@"squareNoteCursor"];
-}
-
-+ (NSCursor *)highlightNoteCursor {
- return [self customCursorWithName:@"highlightNoteCursor"];
-}
-
-+ (NSCursor *)underlineNoteCursor {
- return [self customCursorWithName:@"underlineNoteCursor"];
-}
-
-+ (NSCursor *)strikeOutNoteCursor {
- return [self customCursorWithName:@"strikeOutNoteCursor"];
-}
-
-+ (NSCursor *)lineNoteCursor {
- return [self customCursorWithName:@"lineNoteCursor"];
-}
-
-+ (NSCursor *)inkNoteCursor {
- return [self customCursorWithName:@"inkNoteCursor"];
-}
-
-+ (NSCursor *)emptyCursor {
- static NSCursor *emptyCursor = nil;
- if (nil == emptyCursor) {
- NSImage *cursorImage = [[NSImage alloc] initWithSize:NSMakeSize(16.0,
16.0)];
- emptyCursor = [[NSCursor alloc] initWithImage:cursorImage
hotSpot:NSMakePoint(8.0, 8.0)];
- }
- return emptyCursor;
-}
-
-+ (NSCursor *)laserPointerCursorWithColor:(NSInteger)color {
- static NSPointerArray *laserPointerCursors = nil;
- if (laserPointerCursors == nil) {
- laserPointerCursors = [NSPointerArray strongObjectsPointerArray];
- [laserPointerCursors setCount:7];
- }
- NSCursor *cursor = (__bridge id)[laserPointerCursors pointerAtIndex:color
% 7];
- if (nil == cursor) {
- NSImage *cursorImage = [NSImage laserPointerImageWithColor:color % 7];
- cursor = [[NSCursor alloc] initWithImage:cursorImage
hotSpot:NSMakePoint(0.5 * [cursorImage size].width, 0.5 * [cursorImage
size].height)];
- [laserPointerCursors replacePointerAtIndex:color % 7
withPointer:(__bridge void *)cursor];
- }
- return cursor;
-}
-
-+ (NSCursor *)safeLaserPointerCursorWithColor:(NSInteger)color {
- static NSPointerArray *laserPointerCursors = nil;
- if (laserPointerCursors == nil) {
- laserPointerCursors = [NSPointerArray strongObjectsPointerArray];
- [laserPointerCursors setCount:7];
- }
- NSCursor *cursor = (__bridge id)[laserPointerCursors pointerAtIndex:color
% 7];
- if (nil == cursor) {
- NSImage *cursorImage = [NSImage laserPointerImageWithColor:color % 7];
- cursor = [[SKLaserPointerCursor alloc] initWithImage:cursorImage
hotSpot:NSMakePoint(0.5 * [cursorImage size].width, 0.5 * [cursorImage
size].height)];
- [laserPointerCursors replacePointerAtIndex:color % 7
withPointer:(__bridge void *)cursor];
- }
- return cursor;
-}
-
@end
-
-#pragma mark -
-
-static NSWindow *laserPointerWindow = nil;
-
-static inline void hideLaserPointer(void) {
- if (laserPointerWindow) {
- [laserPointerWindow close];
- laserPointerWindow = nil;
- }
-}
-
-@implementation SKLaserPointerCursor
-
-- (void)set {
- if (original_set)
- original_set([NSCursor emptyCursor], _cmd);
- else
- [[NSCursor emptyCursor] set];
-
- NSPoint p = [NSEvent mouseLocation];
- p = NSMakePoint(round(p.x), round(p.y));
- if (laserPointerWindow) {
- [[[[laserPointerWindow contentView] subviews] firstObject]
setImage:[self image]];
- [laserPointerWindow setFrame:SKRectFromCenterAndSize(p,
[laserPointerWindow frame].size) display:YES];
- } else {
- NSImage *image = [self image];
- CGFloat size = [universalaccessDefaults()
doubleForKey:@"mouseDriverCursorSize"];
- CGFloat s = 2.0 * round(0.5 * (size > 0.0 ? size : 1.0) * [image
size].width);
- laserPointerWindow = [[SKAnimatedBorderlessWindow alloc]
initWithContentRect:SKRectFromCenterAndSquareSize(p, s)];
- [laserPointerWindow setLevel:(NSWindowLevel)kCGCursorWindowLevel];
- [laserPointerWindow addImageViewWithImage:image];
- [laserPointerWindow setHidesOnDeactivate:YES];
- [laserPointerWindow orderFrontRegardless];
- }
-}
-
-@end
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
_______________________________________________
Skim-app-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/skim-app-commit