| 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 (systemCursors == nil) {
29 systemCursors = @{
30 @"alias" : [NSCursor dragLinkCursor],
31 @"basic" : [NSCursor arrowCursor],
32 @"click" : [NSCursor pointingHandCursor],
33 @"contextMenu" : [NSCursor contextualMenuCursor],
34 @"copy" : [NSCursor dragCopyCursor],
35 @"disappearing" : [NSCursor disappearingItemCursor],
36 @"forbidden" : [NSCursor operationNotAllowedCursor],
37 @"grab" : [NSCursor openHandCursor],
38 @"grabbing" : [NSCursor closedHandCursor],
39 @"noDrop" : [NSCursor operationNotAllowedCursor],
40 @"precise" : [NSCursor crosshairCursor],
41 @"text" : [NSCursor IBeamCursor],
42 @"resizeColumn" : [NSCursor resizeLeftRightCursor],
43 @"resizeDown" : [NSCursor resizeDownCursor],
44 @"resizeLeft" : [NSCursor resizeLeftCursor],
45 @"resizeLeftRight" : [NSCursor resizeLeftRightCursor],
46 @"resizeRight" : [NSCursor resizeRightCursor],
47 @"resizeRow" : [NSCursor resizeUpDownCursor],
48 @"resizeUp" : [NSCursor resizeUpCursor],
49 @"resizeUpDown" : [NSCursor resizeUpDownCursor],
50 @"verticalText" : [NSCursor IBeamCursorForVerticalLayout],
51 };
52 }
53 NSCursor* result = [systemCursors objectForKey:kind];
54 if (result == nil) {
55 return [NSCursor arrowCursor];
56 }
57 return result;
58 }
59
60 @interface FlutterMouseCursorPlugin ()
61 /**
62 * Whether the cursor is currently hidden.
63 */
64 @property(nonatomic) BOOL hidden;
65
66 /**
67 * Handles the method call that activates a system cursor.
68 *
69 * Returns a FlutterError if the arguments can not be recognized. Otherwise
70 * returns nil.
71 */
72 - (FlutterError*)activateSystemCursor:(nonnull NSDictionary*)arguments;
73
74 /**
75 * Displays the specified cursor.
76 *
77 * Unhides the cursor before displaying the cursor, and updates
78 * internal states.
79 */
80 - (void)displayCursorObject:(nonnull NSCursor*)cursorObject;
81
82 /**
83 * Hides the cursor.
84 */
85 - (void)hide;
86
87 /**
88 * Handles all method calls from Flutter.
89 */
90 - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result;
91
92 @end
93
94 @implementation FlutterMouseCursorPlugin
95
96 #pragma mark - Private
97
98 NSMutableDictionary* cachedSystemCursors;
99
100 - (instancetype)init {
101 self = [super init];
102 if (self) {
103 cachedSystemCursors = [NSMutableDictionary dictionary];
104 }
105 return self;
106 }
107
108 - (void)dealloc {
109 if (_hidden) {
110 [NSCursor unhide];
111 }
112 }
113
114 - (FlutterError*)activateSystemCursor:(nonnull NSDictionary*)arguments {
115 NSString* kindArg = arguments[kKindKey];
116 if (!kindArg) {
117 return [FlutterError errorWithCode:@"error"
118 message:@"Missing argument"
119 details:@"Missing argument while trying to activate system cursor"];
120 }
121 if ([kindArg isEqualToString:kKindValueNone]) {
122 [self hide];
123 return nil;
124 }
125 NSCursor* cursorObject = [FlutterMouseCursorPlugin cursorFromKind:kindArg];
126 [self displayCursorObject:cursorObject];
127 return nil;
128 }
129
130 - (void)displayCursorObject:(nonnull NSCursor*)cursorObject {
131 [cursorObject set];
132 if (_hidden) {
133 [NSCursor unhide];
134 }
135 _hidden = NO;
136 }
137
138 - (void)hide {
139 if (!_hidden) {
140 [NSCursor hide];
141 }
142 _hidden = YES;
143 }
144
145 + (NSCursor*)cursorFromKind:(NSString*)kind {
146 NSCursor* cachedValue = [cachedSystemCursors objectForKey:kind];
147 if (!cachedValue) {
148 cachedValue = GetCursorForKind(kind);
149 [cachedSystemCursors setValue:cachedValue forKey:kind];
150 }
151 return cachedValue;
152 }
153
154 #pragma mark - FlutterPlugin implementation
155
156 + (void)registerWithRegistrar:(id<FlutterPluginRegistrar>)registrar {
157 FlutterMethodChannel* channel = [FlutterMethodChannel methodChannelWithName:kMouseCursorChannel
158 binaryMessenger:registrar.messenger];
159 FlutterMouseCursorPlugin* instance = [[FlutterMouseCursorPlugin alloc] init];
160 [registrar addMethodCallDelegate:instance channel:channel];
161 }
162
163 - (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
164 NSString* method = call.method;
165 if ([method isEqualToString:kActivateSystemCursorMethod]) {
166 result([self activateSystemCursor:call.arguments]);
167 } else {
168 result(FlutterMethodNotImplemented);
169 }
170 }
171
172 @end
FlutterMouseCursorPlugin
Definition: FlutterMouseCursorPlugin.h:19
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
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:98
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