Flutter macOS Embedder
FlutterView.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 
6 
9 
10 #import <QuartzCore/QuartzCore.h>
11 
14  __weak id<FlutterViewDelegate> _viewDelegate;
17  NSCursor* _lastCursor;
18 }
19 
20 @end
21 
22 @implementation FlutterView
23 
24 - (instancetype)initWithMTLDevice:(id<MTLDevice>)device
25  commandQueue:(id<MTLCommandQueue>)commandQueue
26  delegate:(id<FlutterViewDelegate>)delegate
27  threadSynchronizer:(FlutterThreadSynchronizer*)threadSynchronizer
28  viewIdentifier:(FlutterViewIdentifier)viewIdentifier {
29  self = [super initWithFrame:NSZeroRect];
30  if (self) {
31  [self setWantsLayer:YES];
32  [self setBackgroundColor:[NSColor blackColor]];
33  [self setLayerContentsRedrawPolicy:NSViewLayerContentsRedrawDuringViewResize];
34  _viewIdentifier = viewIdentifier;
35  _viewDelegate = delegate;
36  _threadSynchronizer = threadSynchronizer;
37  _surfaceManager = [[FlutterSurfaceManager alloc] initWithDevice:device
38  commandQueue:commandQueue
39  layer:self.layer
40  delegate:self];
41  }
42  return self;
43 }
44 
45 - (void)onPresent:(CGSize)frameSize withBlock:(dispatch_block_t)block {
46  [_threadSynchronizer performCommitForView:_viewIdentifier size:frameSize notify:block];
47 }
48 
50  return _surfaceManager;
51 }
52 
53 - (void)reshaped {
54  CGSize scaledSize = [self convertSizeToBacking:self.bounds.size];
55  [_threadSynchronizer beginResizeForView:_viewIdentifier
56  size:scaledSize
57  notify:^{
58  [_viewDelegate viewDidReshape:self];
59  }];
60 }
61 
62 - (void)setBackgroundColor:(NSColor*)color {
63  self.layer.backgroundColor = color.CGColor;
64 }
65 
66 #pragma mark - NSView overrides
67 
68 - (void)setFrameSize:(NSSize)newSize {
69  [super setFrameSize:newSize];
70  [self reshaped];
71 }
72 
73 /**
74  * Declares that the view uses a flipped coordinate system, consistent with Flutter conventions.
75  */
76 - (BOOL)isFlipped {
77  return YES;
78 }
79 
80 - (BOOL)isOpaque {
81  return YES;
82 }
83 
84 /**
85  * Declares that the initial mouse-down when the view is not in focus will send an event to the
86  * view.
87  */
88 - (BOOL)acceptsFirstMouse:(NSEvent*)event {
89  return YES;
90 }
91 
92 - (BOOL)acceptsFirstResponder {
93  // This is to ensure that FlutterView does not take first responder status from TextInputPlugin
94  // on mouse clicks.
95  return [_viewDelegate viewShouldAcceptFirstResponder:self];
96 }
97 
98 - (void)didUpdateMouseCursor:(NSCursor*)cursor {
99  _lastCursor = cursor;
100 }
101 
102 // Restores mouse cursor. There are few cases when this is needed and framework will not handle this
103 // automatically:
104 // - When mouse cursor leaves subview of FlutterView (technically still within bound of FlutterView
105 // tracking area so the framework won't be notified)
106 // - When context menu above FlutterView is closed. Context menu will change current cursor to arrow
107 // and will not restore it back.
108 - (void)cursorUpdate:(NSEvent*)event {
109  // Make sure to not override cursor when over a platform view.
110  NSPoint mouseLocation = [[self superview] convertPoint:event.locationInWindow fromView:nil];
111  NSView* hitTestView = [self hitTest:mouseLocation];
112  if (hitTestView != self) {
113  return;
114  }
115  [_lastCursor set];
116  // It is possible that there is a platform view with NSTrackingArea below flutter content.
117  // This could override the mouse cursor as a result of mouse move event. There is no good way
118  // to prevent that short of swizzling [NSCursor set], so as a workaround force flutter cursor
119  // in next runloop turn. This is not ideal, as it may cause the cursor flicker a bit.
120  [[NSRunLoop currentRunLoop] performBlock:^{
121  [_lastCursor set];
122  }];
123 }
124 
125 - (void)viewDidChangeBackingProperties {
126  [super viewDidChangeBackingProperties];
127  // Force redraw
128  [_viewDelegate viewDidReshape:self];
129 }
130 
131 - (BOOL)layer:(CALayer*)layer
132  shouldInheritContentsScale:(CGFloat)newScale
133  fromWindow:(NSWindow*)window {
134  return YES;
135 }
136 
137 #pragma mark - NSAccessibility overrides
138 
139 - (BOOL)isAccessibilityElement {
140  return YES;
141 }
142 
143 - (NSAccessibilityRole)accessibilityRole {
144  return NSAccessibilityGroupRole;
145 }
146 
147 - (NSString*)accessibilityLabel {
148  // TODO(chunhtai): Provides a way to let developer customize the accessibility
149  // label.
150  // https://github.com/flutter/flutter/issues/75446
151  NSString* applicationName =
152  [NSBundle.mainBundle objectForInfoDictionaryKey:@"CFBundleDisplayName"];
153  if (!applicationName) {
154  applicationName = [NSBundle.mainBundle objectForInfoDictionaryKey:@"CFBundleName"];
155  }
156  return applicationName;
157 }
158 
159 @end
FlutterView()::_lastCursor
NSCursor * _lastCursor
Definition: FlutterView.mm:17
FlutterView::surfaceManager
FlutterSurfaceManager * surfaceManager
Definition: FlutterView.h:57
FlutterSurfaceManager.h
FlutterSurfaceManager
Definition: FlutterSurfaceManager.h:44
FlutterView()::_surfaceManager
FlutterSurfaceManager * _surfaceManager
Definition: FlutterView.mm:16
FlutterView()::_viewIdentifier
FlutterViewIdentifier _viewIdentifier
Definition: FlutterView.mm:13
FlutterSurfaceManagerDelegate-p
Definition: FlutterSurfaceManager.h:27
FlutterThreadSynchronizer
Definition: FlutterThreadSynchronizer.h:18
FlutterView()::_threadSynchronizer
FlutterThreadSynchronizer * _threadSynchronizer
Definition: FlutterView.mm:15
FlutterView
Definition: FlutterView.h:35
FlutterThreadSynchronizer.h
FlutterView.h
FlutterViewIdentifier
int64_t FlutterViewIdentifier
Definition: FlutterViewController.h:21
FlutterView()::_viewDelegate
__weak id< FlutterViewDelegate > _viewDelegate
Definition: FlutterView.mm:14
FlutterViewDelegate-p
Definition: FlutterView.h:18
_threadSynchronizer
FlutterThreadSynchronizer * _threadSynchronizer
Definition: FlutterEngine.mm:458