Skip to content
This repository was archived by the owner on Feb 25, 2025. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ci/licenses_golden/licenses_flutter
Original file line number Diff line number Diff line change
Expand Up @@ -957,6 +957,8 @@ FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEngin
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterExternalTextureGL.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterExternalTextureGL.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMouseCursorPlugin.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterMouseCursorPlugin.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputModel.h
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputModel.mm
FILE: ../../../flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.h
Expand Down
2 changes: 2 additions & 0 deletions shell/platform/darwin/macos/BUILD.gn
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ source_set("flutter_framework_source") {
"framework/Source/FlutterEngine_Internal.h",
"framework/Source/FlutterExternalTextureGL.h",
"framework/Source/FlutterExternalTextureGL.mm",
"framework/Source/FlutterMouseCursorPlugin.h",
"framework/Source/FlutterMouseCursorPlugin.mm",
"framework/Source/FlutterTextInputModel.h",
"framework/Source/FlutterTextInputModel.mm",
"framework/Source/FlutterTextInputPlugin.h",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import <Cocoa/Cocoa.h>

#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterBinaryMessenger.h"
#import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterViewController.h"

/**
* A plugin to handle mouse cursor.
*
* Responsible for bridging the native macOS mouse cursor system with the
* Flutter framework mouse cursor classes, via system channels.
*/
@interface FlutterMouseCursorPlugin : NSObject <FlutterPlugin>

@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#import <objc/message.h>

#import "FlutterMouseCursorPlugin.h"
#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterCodecs.h"

static NSString* const kMouseCursorChannel = @"flutter/mousecursor";

static NSString* const kActivateSystemCursorMethod = @"activateSystemCursor";
static NSString* const kKindKey = @"kind";

static NSString* const kKindValueNone = @"none";

/**
* Maps a Flutter's constant to a platform's cursor object.
*
* Returns the arrow cursor for unknown constants, including kSystemShapeNone.
*/
static NSCursor* GetCursorForKind(NSString* kind) {
// The following mapping must be kept in sync with Flutter framework's
// mouse_cursor.dart
if ([kind isEqualToString:@"basic"])
return [NSCursor arrowCursor];
else if ([kind isEqualToString:@"click"])
return [NSCursor pointingHandCursor];
else if ([kind isEqualToString:@"text"])
return [NSCursor IBeamCursor];
else if ([kind isEqualToString:@"forbidden"])
return [NSCursor operationNotAllowedCursor];
else if ([kind isEqualToString:@"grab"])
return [NSCursor openHandCursor];
else if ([kind isEqualToString:@"grabbing"])
return [NSCursor closedHandCursor];
else
return [NSCursor arrowCursor];
}

@interface FlutterMouseCursorPlugin ()
/**
* Whether the cursor is currently hidden.
*/
@property(nonatomic) BOOL hidden;

/**
* Handles the method call that activates a system cursor.
*
* Returns a FlutterError if the arguments can not be recognized. Otherwise
* returns nil.
*/
- (FlutterError*)activateSystemCursor:(nonnull NSDictionary*)arguments;

/**
* Displays the specified cursor.
*
* Unhides the cursor before displaying the cursor, and updates
* internal states.
*/
- (void)displayCursorObject:(nonnull NSCursor*)cursorObject;

/**
* Hides the cursor.
*/
- (void)hide;

/**
* Handles all method calls from Flutter.
*/
- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result;

@end

@implementation FlutterMouseCursorPlugin

#pragma mark - Private

NSMutableDictionary* cachedSystemCursors;

- (instancetype)init {
self = [super init];
if (self) {
cachedSystemCursors = [NSMutableDictionary dictionary];
}
return self;
}

- (void)dealloc {
if (_hidden) {
[NSCursor unhide];
}
}

- (FlutterError*)activateSystemCursor:(nonnull NSDictionary*)arguments {
NSString* kindArg = arguments[kKindKey];
if (!kindArg) {
return [FlutterError errorWithCode:@"error"
message:@"Missing argument"
details:@"Missing argument while trying to activate system cursor"];
}
if ([kindArg isEqualToString:kKindValueNone]) {
[self hide];
return nil;
}
NSCursor* cursorObject = [FlutterMouseCursorPlugin cursorFromKind:kindArg];
[self displayCursorObject:cursorObject];
return nil;
}

- (void)displayCursorObject:(nonnull NSCursor*)cursorObject {
[cursorObject set];
if (_hidden) {
[NSCursor unhide];
}
_hidden = NO;
}

- (void)hide {
if (!_hidden) {
[NSCursor hide];
}
_hidden = YES;
}

+ (NSCursor*)cursorFromKind:(NSString*)kind {
NSCursor* cachedValue = [cachedSystemCursors objectForKey:kind];
if (!cachedValue) {
cachedValue = GetCursorForKind(kind);
[cachedSystemCursors setValue:cachedValue forKey:kind];
}
return cachedValue;
}

#pragma mark - FlutterPlugin implementation

+ (void)registerWithRegistrar:(id<FlutterPluginRegistrar>)registrar {
FlutterMethodChannel* channel = [FlutterMethodChannel methodChannelWithName:kMouseCursorChannel
binaryMessenger:registrar.messenger];
FlutterMouseCursorPlugin* instance = [[FlutterMouseCursorPlugin alloc] init];
[registrar addMethodCallDelegate:instance channel:channel];
}

- (void)handleMethodCall:(FlutterMethodCall*)call result:(FlutterResult)result {
NSString* method = call.method;
if ([method isEqualToString:kActivateSystemCursorMethod]) {
result([self activateSystemCursor:call.arguments]);
} else {
result(FlutterMethodNotImplemented);
}
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#import "flutter/shell/platform/darwin/common/framework/Headers/FlutterCodecs.h"
#import "flutter/shell/platform/darwin/macos/framework/Headers/FlutterEngine.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterEngine_Internal.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterMouseCursorPlugin.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterTextInputPlugin.h"
#import "flutter/shell/platform/darwin/macos/framework/Source/FlutterView.h"
#import "flutter/shell/platform/embedder/embedder.h"
Expand Down Expand Up @@ -350,6 +351,7 @@ - (void)configureTrackingArea {
}

- (void)addInternalPlugins {
[FlutterMouseCursorPlugin registerWithRegistrar:[self registrarForPlugin:@"mousecursor"]];
_textInputPlugin = [[FlutterTextInputPlugin alloc] initWithViewController:self];
_keyEventChannel =
[FlutterBasicMessageChannel messageChannelWithName:@"flutter/keyevent"
Expand Down