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 
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 
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 {
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