| Flutter macOS Embedder |

FlutterMouseCursorPlugin.mm
Go to the documentation of this file.
1 // Copyright 2013 The Flutter Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #import <objc/message.h>
6
7 #import "FlutterMouseCursorPlugin.h"
8 #import "flutter/shell/platform/darwin/common/framework/Headers/FlutterCodecs.h"
9
10 static NSString* const kMouseCursorChannel = @"flutter/mousecursor";
11
12 static NSString* const kActivateSystemCursorMethod = @"activateSystemCursor";
13 static NSString* const kKindKey = @"kind";
14
15 static NSString* const kKindValueNone = @"none";
16
17 static NSDictionary* systemCursors;
18
19 /**
20 * Maps a Flutter's constant to a platform's cursor object.
21 *
22 * Returns the arrow cursor for unknown constants, including kSystemShapeNone.
23 */
24 static NSCursor* GetCursorForKind(NSString* kind) {
25 // The following mapping must be kept in sync with Flutter framework's
26 // mouse_cursor.dart
27
28 if ([kind isEqualToString:kKindValueNone]) {
29 NSImage* image = [[NSImage alloc] initWithSize:NSMakeSize(1, 1)];
30 return [[NSCursor alloc] initWithImage:image hotSpot:NSMakePoint(0, 0)];
31 }
32
33 if (systemCursors == nil) {
34 systemCursors = @{
35 @"alias" : [NSCursor dragLinkCursor],
36 @"basic" : [NSCursor arrowCursor],
37 @"click" : [NSCursor pointingHandCursor],
38 @"contextMenu" : [NSCursor contextualMenuCursor],
39 @"copy" : [NSCursor dragCopyCursor],
40 @"disappearing" : [NSCursor disappearingItemCursor],
41 @"forbidden" : [NSCursor operationNotAllowedCursor],
42 @"grab" : [NSCursor openHandCursor],
43 @"grabbing" : [NSCursor closedHandCursor],
44 @"noDrop" : [NSCursor operationNotAllowedCursor],
45 @"precise" : [NSCursor crosshairCursor],
46 @"text" : [NSCursor IBeamCursor],
47 @"resizeColumn" : [NSCursor resizeLeftRightCursor],
48 @"resizeDown" : [NSCursor resizeDownCursor],
49 @"resizeLeft" : [NSCursor resizeLeftCursor],
50 @"resizeLeftRight" : [NSCursor resizeLeftRightCursor],
51 @"resizeRight" : [NSCursor resizeRightCursor],
52 @"resizeRow" : [NSCursor resizeUpDownCursor],
53 @"resizeUp" : [NSCursor resizeUpCursor],
54 @"resizeUpDown" : [NSCursor resizeUpDownCursor],
55 @"verticalText" : [NSCursor IBeamCursorForVerticalLayout],
56 };
57 }
58 NSCursor* result = [systemCursors objectForKey:kind];
59 if (result == nil) {
60 return [NSCursor arrowCursor];
61 }
62 return result;
63 }
64
65 @interface FlutterMouseCursorPlugin ()
66
67 @property(nonatomic, weak) id<FlutterMouseCursorPluginDelegate> delegate;
68
69 /**
70 * Handles the method call that activates a system cursor.
71 *
72 * Returns a FlutterError if the arguments can not be recognized. Otherwise
73 * returns nil.
74 */
75 - (FlutterError*)activateSystemCursor:(nonnull NSDictionary*)arguments;
76
77 /**
78 * Displays the specified cursor.
79 *
80 * Unhides the cursor before displaying the cursor, and updates
81 * internal states.
82 */
83 - (void)displayCursorObject:(nonnull NSCursor*)cursorObject;
84
85 /**
86 * Handles all method calls from Flutter.
87 */
88 - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result;
89
90 @end
91
92 @implementation FlutterMouseCursorPlugin
93
94 #pragma mark - Private
95
96 NSMutableDictionary* cachedSystemCursors;
97
98 - (instancetype)init {
99 self = [super init];
100 if (self) {
101 cachedSystemCursors = [NSMutableDictionary dictionary];
102 }
103 return self;
104 }
105
106 - (FlutterError*)activateSystemCursor:(nonnull NSDictionary*)arguments {
107 NSString* kindArg = arguments[kKindKey];
108 if (!kindArg) {
109 return [FlutterError errorWithCode:@"error"
110 message:@"Missing argument"
111 details:@"Missing argument while trying to activate system cursor"];
112 }
113
114 NSCursor* cursorObject = [FlutterMouseCursorPlugin cursorFromKind:kindArg];
115 [self displayCursorObject:cursorObject];
116 return nil;
117 }
118
119 - (void)displayCursorObject:(nonnull NSCursor*)cursorObject {
120 [cursorObject set];
121 [self.delegate didUpdateMouseCursor:cursorObject];
122 }
123
124 + (NSCursor*)cursorFromKind:(NSString*)kind {
125 NSCursor* cachedValue = [cachedSystemCursors objectForKey:kind];
126 if (!cachedValue) {
127 cachedValue = GetCursorForKind(kind);
128 [cachedSystemCursors setValue:cachedValue forKey:kind];
129 }
130 return cachedValue;
131 }
132
133 #pragma mark - FlutterPlugin implementation
134
135 + (void)registerWithRegistrar:(id<FlutterPluginRegistrar>)registrar {
136 [self registerWithRegistrar:registrar delegate:nil];
137 }
138
139 + (void)registerWithRegistrar:(id<FlutterPluginRegistrar>)registrar
140 delegate:(id<FlutterMouseCursorPluginDelegate>)delegate {
141 FlutterMethodChannel* channel = [FlutterMethodChannel methodChannelWithName:kMouseCursorChannel
142 binaryMessenger:registrar.messenger];
143 FlutterMouseCursorPlugin* instance = [[FlutterMouseCursorPlugin alloc] init];
144 instance.delegate = delegate;
145 [registrar addMethodCallDelegate:instance channel:channel];
146 }
147
148 - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
149 NSString* method = call.method;
150 if ([method isEqualToString:kActivateSystemCursorMethod]) {
151 result([self activateSystemCursor:call.arguments]);
152 } else {
153 result(FlutterMethodNotImplemented);
154 }
155 }
156
157 @end
FlutterMouseCursorPlugin
Definition: FlutterMouseCursorPlugin.h:23
FlutterMethodChannel
Definition: FlutterChannels.h:220
FlutterMethodNotImplemented
FLUTTER_DARWIN_EXPORT NSObject const * FlutterMethodNotImplemented
FlutterError
Definition: FlutterCodecs.h:246
FlutterMethodCall::method
NSString * method
Definition: FlutterCodecs.h:233
kActivateSystemCursorMethod
static NSString *const kActivateSystemCursorMethod
Definition: FlutterMouseCursorPlugin.mm:12
+[FlutterError errorWithCode:message:details:]
instancetype errorWithCode:message:details:(NSString *code,[message] NSString *_Nullable message,[details] id _Nullable details)
FlutterPluginRegistrar-p
Definition: FlutterPluginRegistrarMacOS.h:28
FlutterMouseCursorPlugin.h
-[FlutterPluginRegistrar-p addMethodCallDelegate:channel:]
void addMethodCallDelegate:channel:(nonnull id< FlutterPlugin > delegate,[channel] nonnull FlutterMethodChannel *channel)
FlutterMethodCall
Definition: FlutterCodecs.h:220
kKindKey
static NSString *const kKindKey
Definition: FlutterMouseCursorPlugin.mm:13
FlutterMouseCursorPluginDelegate-p
Definition: FlutterMouseCursorPlugin.h:13
FlutterResult
void(^ FlutterResult)(id _Nullable result)
Definition: FlutterChannels.h:194
systemCursors
static NSDictionary * systemCursors
Definition: FlutterMouseCursorPlugin.mm:17
FlutterCodecs.h
cachedSystemCursors
NSMutableDictionary * cachedSystemCursors
Definition: FlutterMouseCursorPlugin.mm:96
kMouseCursorChannel
static NSString *const kMouseCursorChannel
Definition: FlutterMouseCursorPlugin.mm:10
+[FlutterMethodChannel methodChannelWithName:binaryMessenger:]
instancetype methodChannelWithName:binaryMessenger:(NSString *name,[binaryMessenger] NSObject< FlutterBinaryMessenger > *messenger)
GetCursorForKind
static NSCursor * GetCursorForKind(NSString *kind)
Definition: FlutterMouseCursorPlugin.mm:24
FlutterMethodCall::arguments
id arguments
Definition: FlutterCodecs.h:238
kKindValueNone
static NSString *const kKindValueNone
Definition: FlutterMouseCursorPlugin.mm:15