Flutter macOS Embedder
FlutterWindowController.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 #include <Foundation/Foundation.h>
7 
12 
14 
15 // A delegate for a Flutter managed window.
16 @interface FlutterWindowOwner : NSObject <NSWindowDelegate, FlutterViewSizingDelegate> {
17  // Strong reference to the window. This is the only strong reference to the
18  // window.
19  NSWindow* _window;
21  std::optional<flutter::Isolate> _isolate;
23 
24  // Extra size constraints coming from the window positioner.
26 }
27 
28 @property(readonly, nonatomic) NSWindow* window;
29 @property(readonly, nonatomic) FlutterViewController* flutterViewController;
30 @property(readwrite, nonatomic) BOOL closeWhenParentResignsKey;
31 
32 - (instancetype)initWithWindow:(NSWindow*)window
33  flutterViewController:(FlutterViewController*)viewController
34  creationRequest:(const FlutterWindowCreationRequest&)creationRequest;
35 
36 @end
37 
39 
40 - (void)flutterSetContentSize:(FlutterWindowSize)contentSize;
41 - (void)flutterSetConstraints:(FlutterWindowConstraints)constraints;
42 
43 @end
44 
45 @implementation NSWindow (FlutterWindowSizing)
46 - (void)flutterSetContentSize:(FlutterWindowSize)contentSize {
47  [self setContentSize:NSMakeSize(contentSize.width, contentSize.height)];
48 }
49 
50 - (void)flutterSetConstraints:(FlutterWindowConstraints)constraints {
51  NSSize size = [self frameRectForContentRect:self.frame].size;
52  NSSize originalSize = size;
53  [self setContentMinSize:NSMakeSize(constraints.min_width, constraints.min_height)];
54  size.width = std::max(size.width, constraints.min_width);
55  size.height = std::max(size.height, constraints.min_height);
56  if (constraints.max_width > 0 && constraints.max_height > 0) {
57  [self setContentMaxSize:NSMakeSize(constraints.max_width, constraints.max_height)];
58  size.width = std::min(size.width, constraints.max_width);
59  size.height = std::min(size.height, constraints.max_height);
60  } else {
61  [self setContentMaxSize:NSMakeSize(CGFLOAT_MAX, CGFLOAT_MAX)];
62  }
63  if (!NSEqualSizes(originalSize, size)) {
64  [self setContentSize:size];
65  }
66 }
67 
68 @end
69 
70 @interface FlutterWindowController () {
71  NSMutableArray<FlutterWindowOwner*>* _windows;
72 }
73 
74 - (void)windowDidResignKey:(FlutterWindowOwner*)window;
75 
76 @end
77 
78 @implementation FlutterWindowOwner
79 
80 @synthesize window = _window;
82 
83 - (instancetype)initWithWindow:(NSWindow*)window
84  flutterViewController:(FlutterViewController*)viewController
85  creationRequest:(const FlutterWindowCreationRequest&)creationRequest {
86  if (self = [super init]) {
87  _window = window;
88  _flutterViewController = viewController;
89  _creationRequest = creationRequest;
91  }
92  return self;
93 }
94 
95 - (void)windowDidBecomeKey:(NSNotification*)notification {
96  [_flutterViewController.engine windowDidBecomeKey:_flutterViewController.viewIdentifier];
97 }
98 
99 - (void)windowDidResignKey:(NSNotification*)notification {
100  [_flutterViewController.engine windowDidResignKey:_flutterViewController.viewIdentifier];
101  [[_flutterViewController.engine windowController] windowDidResignKey:self];
102 }
103 
104 - (BOOL)windowShouldClose:(NSWindow*)sender {
105  flutter::IsolateScope isolate_scope(*_isolate);
107  return NO;
108 }
109 
110 - (void)windowWillClose {
112 }
113 
114 - (void)windowDidResize:(NSNotification*)notification {
115  flutter::IsolateScope isolate_scope(*_isolate);
117 }
118 
119 // Miniaturize does not trigger resize event, but for now there
120 // is no other way to get notification about the state change.
121 - (void)windowDidMiniaturize:(NSNotification*)notification {
122  flutter::IsolateScope isolate_scope(*_isolate);
124 }
125 
126 // Deminiaturize does not trigger resize event, but for now there
127 // is no other way to get notification about the state change.
128 - (void)windowDidDeminiaturize:(NSNotification*)notification {
129  flutter::IsolateScope isolate_scope(*_isolate);
131 }
132 
133 - (void)windowWillEnterFullScreen:(NSNotification*)notification {
134  flutter::IsolateScope isolate_scope(*_isolate);
136 }
137 
138 - (void)windowWillExitFullScreen:(NSNotification*)notification {
139  flutter::IsolateScope isolate_scope(*_isolate);
141 }
142 
143 - (std::optional<NSSize>)minimumViewSize:(FlutterView*)view {
145  return NSMakeSize(_creationRequest.constraints.min_width,
147  } else {
148  return std::nullopt;
149  }
150 }
151 
152 - (std::optional<NSSize>)maximumViewSize:(FlutterView*)view {
154  // Window is not sized to contents.
155  return std::nullopt;
156  }
157  NSSize screenSize = self.window.screen.visibleFrame.size;
158  double width = screenSize.width;
159  width = std::min(width, _creationRequest.constraints.max_width);
160  if (_positionerSizeConstraints.width > 0) {
161  width = std::min(width, _positionerSizeConstraints.width);
162  }
163  double height = screenSize.height;
164  height = std::min(height, _creationRequest.constraints.max_height);
165  if (_positionerSizeConstraints.height > 0) {
166  height = std::min(height, _positionerSizeConstraints.height);
167  }
168  return NSMakeSize(width, height);
169 }
170 
171 // Returns the frame that includes all screen. This is used to flip coordinates
172 // of individual screen to match Flutter coordinate system.
173 static NSRect ComputeGlobalScreenFrame() {
174  NSRect frame = NSZeroRect;
175  for (NSScreen* screen in [NSScreen screens]) {
176  NSRect screenFrame = screen.frame;
177  if (NSIsEmptyRect(frame)) {
178  frame = screenFrame;
179  } else {
180  frame = NSUnionRect(frame, screenFrame);
181  }
182  }
183  return frame;
184 }
185 
186 static void FlipRect(NSRect& rect, const NSRect& globalScreenFrame) {
187  // Flip the y coordinate to match Flutter coordinate system.
188  rect.origin.y = (globalScreenFrame.origin.y + globalScreenFrame.size.height) -
189  (rect.origin.y + rect.size.height);
190 }
191 
192 - (void)updatePosition {
193  [self viewDidUpdateContents:self.flutterViewController.flutterView
194  withSize:self.flutterViewController.flutterView.bounds.size];
195 }
196 
197 - (void)viewDidUpdateContents:(FlutterView*)view withSize:(NSSize)newSize {
198  if (_creationRequest.on_get_window_position == nullptr) {
199  // There is no positioner associated with this window.
200  return;
201  }
202 
203  NSRect globalScreenFrame = ComputeGlobalScreenFrame();
204 
205  NSRect parentRect =
206  [self.window.parentWindow contentRectForFrameRect:self.window.parentWindow.frame];
207  FlipRect(parentRect, globalScreenFrame);
208 
209  NSRect screenRect = [self.window.screen visibleFrame];
210  FlipRect(screenRect, globalScreenFrame);
211 
212  flutter::IsolateScope isolate_scope(*_isolate);
215  FlutterWindowRect::fromNSRect(screenRect));
216 
217  NSRect positionRect = position->toNSRect();
218  FlipRect(positionRect, globalScreenFrame);
219 
220  [self.window setFrame:positionRect display:NO animate:NO];
221 
222  free(position);
223 
224  // For windows sized to contents if the positioner size doesn't match actual size
225  // the requested size needs to be passed through constraints.
226  if (view.sizedToContents &&
227  (positionRect.size.width < newSize.width || positionRect.size.height < newSize.height)) {
228  _positionerSizeConstraints = positionRect.size;
229  [view constraintsDidChange];
230  } else {
231  // Only show the window initially if positioner agrees with the size.
232  self.window.alphaValue = 1.0;
233  }
234 }
235 
236 - (void)setConstraints:(FlutterWindowConstraints)constraints {
237  if (_flutterViewController.flutterView.sizedToContents) {
238  self->_creationRequest.constraints = constraints;
239  [_flutterViewController.flutterView constraintsDidChange];
240  } else {
241  [self.window flutterSetConstraints:constraints];
242  }
243 }
244 
245 @end
246 
247 @interface FlutterPopupWindow : NSPanel
248 @end
249 
250 @implementation FlutterPopupWindow
251 
252 - (BOOL)canBecomeKeyWindow {
253  return NO;
254 }
255 
256 - (BOOL)acceptsFirstResponder {
257  return NO;
258 }
259 
260 - (BOOL)canBecomeMainWindow {
261  return NO;
262 }
263 
264 @end
265 
266 @implementation FlutterWindowController
267 
268 - (instancetype)init {
269  self = [super init];
270  if (self != nil) {
271  _windows = [NSMutableArray array];
272  }
273  return self;
274 }
275 
276 - (FlutterViewIdentifier)createDialogWindow:(const FlutterWindowCreationRequest*)request {
277  FlutterViewController* controller = [[FlutterViewController alloc] initWithEngine:_engine
278  nibName:nil
279  bundle:nil];
280 
281  NSWindow* window = [[NSWindow alloc] init];
282  // If this is not set there will be double free on window close when
283  // using ARC.
284  [window setReleasedWhenClosed:NO];
285 
286  window.contentViewController = controller;
287  window.styleMask =
288  NSWindowStyleMaskResizable | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable;
289  window.collectionBehavior = NSWindowCollectionBehaviorFullScreenAuxiliary;
290  if (request->has_size) {
291  [window flutterSetContentSize:request->size];
292  }
293  if (request->has_constraints) {
294  [window flutterSetConstraints:request->constraints];
295  }
296 
297  FlutterWindowOwner* owner = [[FlutterWindowOwner alloc] initWithWindow:window
298  flutterViewController:controller
299  creationRequest:*request];
300  window.delegate = owner;
301  [_windows addObject:owner];
302 
303  NSWindow* parent = nil;
304 
305  if (request->parent_view_id != 0) {
306  for (FlutterWindowOwner* owner in _windows) {
307  if (owner.flutterViewController.viewIdentifier == request->parent_view_id) {
308  parent = owner.window;
309  break;
310  }
311  }
312  if (parent == nil) {
313  FML_LOG(WARNING) << "Failed to find parent window for ID " << request->parent_view_id;
314  }
315  }
316 
317  if (parent != nil) {
318  dispatch_async(dispatch_get_main_queue(), ^{
319  // beginCriticalSheet blocks with nested run loop until the
320  // sheet animation is finished.
321  [parent beginCriticalSheet:window
322  completionHandler:^(NSModalResponse response){
323  }];
324  });
325 
326  } else {
327  [window setIsVisible:YES];
328  [window makeKeyAndOrderFront:nil];
329  }
330 
331  return controller.viewIdentifier;
332 }
333 
334 - (FlutterViewIdentifier)createTooltipWindow:(const FlutterWindowCreationRequest*)request {
335  FlutterViewController* controller = [[FlutterViewController alloc] initWithEngine:_engine
336  nibName:nil
337  bundle:nil];
338 
339  NSWindow* window = [[NSWindow alloc] init];
340  // If this is not set there will be double free on window close when
341  // using ARC.
342  [window setReleasedWhenClosed:NO];
343 
344  window.contentViewController = controller;
345  window.styleMask = NSWindowStyleMaskBorderless;
346  window.hasShadow = NO;
347  window.opaque = NO;
348  window.backgroundColor = [NSColor clearColor];
349 
350  FlutterWindowOwner* owner = [[FlutterWindowOwner alloc] initWithWindow:window
351  flutterViewController:controller
352  creationRequest:*request];
353 
354  controller.flutterView.sizingDelegate = owner;
355  controller.flutterView.backgroundColor = [NSColor clearColor];
356  // Resend configure event after setting the sizing delegate.
357  [controller.flutterView constraintsDidChange];
358  owner.closeWhenParentResignsKey = YES;
359 
360  window.delegate = owner;
361  [_windows addObject:owner];
362 
363  NSWindow* parent = nil;
364 
365  FML_DCHECK(request->parent_view_id != 0);
366  for (FlutterWindowOwner* owner in _windows) {
367  if (owner.flutterViewController.viewIdentifier == request->parent_view_id) {
368  parent = owner.window;
369  break;
370  }
371  }
372 
373  NSAssert(parent != nil, @"Tooltip window must have a parent window.");
374 
375  window.ignoresMouseEvents = YES;
376  window.collectionBehavior = NSWindowCollectionBehaviorAuxiliary;
377  [parent addChildWindow:window ordered:NSWindowAbove];
378  window.alphaValue = 0.0;
379  return controller.viewIdentifier;
380 }
381 
382 - (FlutterViewIdentifier)createPopupWindow:(const FlutterWindowCreationRequest*)request {
383  FlutterViewController* controller = [[FlutterViewController alloc] initWithEngine:_engine
384  nibName:nil
385  bundle:nil];
386  // By default this is kFlutterMouseTrackingModeInKeyWindow but popup window is never
387  // key window.
388  controller.mouseTrackingMode = kFlutterMouseTrackingModeInActiveApp;
389 
390  NSWindow* window = [[FlutterPopupWindow alloc] init];
391  // If this is not set there will be double free on window close when
392  // using ARC.
393  [window setReleasedWhenClosed:NO];
394 
395  window.contentViewController = controller;
396  window.styleMask = NSWindowStyleMaskBorderless;
397  window.hasShadow = NO;
398  window.opaque = NO;
399  window.backgroundColor = [NSColor clearColor];
400 
401  FlutterWindowOwner* w = [[FlutterWindowOwner alloc] initWithWindow:window
402  flutterViewController:controller
403  creationRequest:*request];
404 
405  controller.flutterView.sizingDelegate = w;
406  [controller.flutterView setBackgroundColor:[NSColor clearColor]];
407  // Resend configure event after setting the sizing delegate.
408  [controller.flutterView constraintsDidChange];
410 
411  window.delegate = w;
412  [_windows addObject:w];
413 
414  NSWindow* parent = nil;
415 
416  FML_DCHECK(request->parent_view_id != 0);
417  for (FlutterWindowOwner* owner in _windows) {
418  if (owner.flutterViewController.viewIdentifier == request->parent_view_id) {
419  parent = owner.window;
420  break;
421  }
422  }
423 
424  NSAssert(parent != nil, @"Popup window must have a parent window.");
425 
426  window.collectionBehavior = NSWindowCollectionBehaviorAuxiliary;
427  [parent addChildWindow:window ordered:NSWindowAbove];
428  window.alphaValue = 0.0;
429  return controller.viewIdentifier;
430 }
431 
432 - (FlutterViewIdentifier)createRegularWindow:(const FlutterWindowCreationRequest*)request {
433  FlutterViewController* controller = [[FlutterViewController alloc] initWithEngine:_engine
434  nibName:nil
435  bundle:nil];
436 
437  NSWindow* window = [[NSWindow alloc] init];
438  // If this is not set there will be double free on window close when
439  // using ARC.
440  [window setReleasedWhenClosed:NO];
441 
442  window.contentViewController = controller;
443  window.styleMask = NSWindowStyleMaskResizable | NSWindowStyleMaskTitled |
444  NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
445  if (request->has_size) {
446  [window flutterSetContentSize:request->size];
447  }
448  if (request->has_constraints) {
449  [window flutterSetConstraints:request->constraints];
450  }
451  [window setIsVisible:YES];
452  [window makeKeyAndOrderFront:nil];
453 
454  FlutterWindowOwner* owner = [[FlutterWindowOwner alloc] initWithWindow:window
455  flutterViewController:controller
456  creationRequest:*request];
457  window.delegate = owner;
458  [_windows addObject:owner];
459 
460  return controller.viewIdentifier;
461 }
462 
463 - (void)destroyWindow:(NSWindow*)window {
464  FlutterWindowOwner* owner = nil;
465  for (FlutterWindowOwner* o in _windows) {
466  if (o.window == window) {
467  owner = o;
468  break;
469  }
470  }
471  if (owner != nil) {
472  [_windows removeObject:owner];
473  for (NSWindow* win in owner.window.sheets) {
474  [self destroyWindow:win];
475  }
476 
477  for (NSWindow* win in owner.window.childWindows) {
478  [self destroyWindow:win];
479  }
480  // Make sure to unregister the controller from the engine and remove the FlutterView
481  // before destroying the window and Flutter NSView.
482  [owner.flutterViewController dispose];
483  owner.window.delegate = nil;
484  [owner.window close];
485  [owner windowWillClose];
486  }
487 }
488 
489 - (void)closeAllWindows {
490  for (FlutterWindowOwner* owner in _windows) {
491  [owner.flutterViewController dispose];
492  [owner.window close];
493  }
494  [_windows removeAllObjects];
495 }
496 
497 static BOOL IsChildAncestor(NSWindow* child, NSWindow* ancestor) {
498  NSWindow* current = child.parentWindow;
499  while (current) {
500  if (current == ancestor) {
501  return YES;
502  }
503  current = current.parentWindow;
504  }
505 
506  return NO;
507 }
508 
509 - (void)windowDidResignKey:(FlutterWindowOwner*)parent {
510  for (FlutterWindowOwner* possibleChild in _windows) {
511  if (possibleChild.closeWhenParentResignsKey &&
512  IsChildAncestor(possibleChild.window, parent.window)) {
513  [possibleChild windowShouldClose:possibleChild.window];
514  }
515  }
516 }
517 
518 @end
519 
520 // NOLINTBEGIN(google-objc-function-naming)
521 
523  int64_t engine_id,
524  const FlutterWindowCreationRequest* request) {
525  FlutterEngine* engine = [FlutterEngine engineForIdentifier:engine_id];
526  [engine enableMultiView];
527  return [engine.windowController createRegularWindow:request];
528 }
529 
531  int64_t engine_id,
532  const FlutterWindowCreationRequest* request) {
533  FlutterEngine* engine = [FlutterEngine engineForIdentifier:engine_id];
534  [engine enableMultiView];
535  return [engine.windowController createDialogWindow:request];
536 }
537 
539  int64_t engine_id,
540  const FlutterWindowCreationRequest* request) {
541  FlutterEngine* engine = [FlutterEngine engineForIdentifier:engine_id];
542  [engine enableMultiView];
543  return [engine.windowController createTooltipWindow:request];
544 }
545 
547  int64_t engine_id,
548  const FlutterWindowCreationRequest* request) {
549  FlutterEngine* engine = [FlutterEngine engineForIdentifier:engine_id];
550  [engine enableMultiView];
551  return [engine.windowController createPopupWindow:request];
552 }
553 
554 void InternalFlutter_Window_Destroy(int64_t engine_id, void* window) {
555  NSWindow* w = (__bridge NSWindow*)window;
556  FlutterEngine* engine = [FlutterEngine engineForIdentifier:engine_id];
557  [engine.windowController destroyWindow:w];
558 }
559 
560 void* InternalFlutter_Window_GetHandle(int64_t engine_id, FlutterViewIdentifier view_id) {
561  FlutterEngine* engine = [FlutterEngine engineForIdentifier:engine_id];
562  FlutterViewController* controller = [engine viewControllerForIdentifier:view_id];
563  return (__bridge void*)controller.view.window;
564 }
565 
567  NSWindow* w = (__bridge NSWindow*)window;
568  NSRect contentRect = [w contentRectForFrameRect:w.frame];
569  return {
570  .width = contentRect.size.width,
571  .height = contentRect.size.height,
572  };
573 }
574 
576  NSWindow* w = (__bridge NSWindow*)window;
577  [w flutterSetContentSize:*size];
578 }
579 
582  const FlutterWindowConstraints* constraints) {
583  NSWindow* w = (__bridge NSWindow*)window;
584  FlutterWindowOwner* owner = (FlutterWindowOwner*)w.delegate;
585  [owner setConstraints:*constraints];
586 }
587 
588 void InternalFlutter_Window_SetTitle(void* window, const char* title) {
589  NSWindow* w = (__bridge NSWindow*)window;
590  w.title = [NSString stringWithUTF8String:title];
591 }
592 
593 void InternalFlutter_Window_SetMaximized(void* window, bool maximized) {
594  NSWindow* w = (__bridge NSWindow*)window;
595  if (maximized & !w.isZoomed) {
596  [w zoom:nil];
597  } else if (!maximized && w.isZoomed) {
598  [w zoom:nil];
599  }
600 }
601 
603  NSWindow* w = (__bridge NSWindow*)window;
604  return w.isZoomed;
605 }
606 
608  NSWindow* w = (__bridge NSWindow*)window;
609  [w miniaturize:nil];
610 }
611 
613  NSWindow* w = (__bridge NSWindow*)window;
614  [w deminiaturize:nil];
615 }
616 
618  NSWindow* w = (__bridge NSWindow*)window;
619  return w.isMiniaturized;
620 }
621 
622 void InternalFlutter_Window_SetFullScreen(void* window, bool fullScreen) {
623  NSWindow* w = (__bridge NSWindow*)window;
624  bool isFullScreen = (w.styleMask & NSWindowStyleMaskFullScreen) != 0;
625  if (fullScreen && !isFullScreen) {
626  [w toggleFullScreen:nil];
627  } else if (!fullScreen && isFullScreen) {
628  [w toggleFullScreen:nil];
629  }
630 }
631 
633  NSWindow* w = (__bridge NSWindow*)window;
634  return (w.styleMask & NSWindowStyleMaskFullScreen) != 0;
635 }
636 
638  NSWindow* w = (__bridge NSWindow*)window;
639  [NSApplication.sharedApplication activateIgnoringOtherApps:YES];
640  [w makeKeyAndOrderFront:nil];
641 }
642 
643 char* InternalFlutter_Window_GetTitle(void* window) {
644  NSWindow* w = (__bridge NSWindow*)window;
645  return strdup(w.title.UTF8String);
646 }
647 
649  NSWindow* w = (__bridge NSWindow*)window;
650  return w.isKeyWindow;
651 }
652 
654  NSWindow* w = (__bridge NSWindow*)window;
655  FlutterWindowOwner* owner = (FlutterWindowOwner*)w.delegate;
656  [owner updatePosition];
657 }
658 
660  NSWindow* w = (__bridge NSWindow*)window;
661  NSWindow* parent = w.parentWindow;
662  if (!parent) {
663  return {0, 0};
664  }
665  NSRect globalScreenFrame = ComputeGlobalScreenFrame();
666 
667  NSRect parentRect = [parent contentRectForFrameRect:parent.frame];
668  FlipRect(parentRect, globalScreenFrame);
669 
670  NSRect childRect = w.frame;
671  FlipRect(childRect, globalScreenFrame);
672 
673  return {
674  .x = childRect.origin.x - parentRect.origin.x,
675  .y = childRect.origin.y - parentRect.origin.y,
676  };
677 }
678 
679 // NOLINTEND(google-objc-function-naming)
#define FLUTTER_DARWIN_EXPORT
Definition: FlutterMacros.h:14
int64_t FlutterViewIdentifier
void InternalFlutter_Window_Activate(void *window)
void * InternalFlutter_Window_GetHandle(int64_t engine_id, FlutterViewIdentifier view_id)
bool InternalFlutter_Window_IsMaximized(void *window)
int64_t InternalFlutter_WindowController_CreateTooltipWindow(int64_t engine_id, const FlutterWindowCreationRequest *request)
int64_t InternalFlutter_WindowController_CreatePopupWindow(int64_t engine_id, const FlutterWindowCreationRequest *request)
FLUTTER_DARWIN_EXPORT void InternalFlutter_Window_SetConstraints(void *window, const FlutterWindowConstraints *constraints)
bool InternalFlutter_Window_IsActivated(void *window)
int64_t InternalFlutter_WindowController_CreateDialogWindow(int64_t engine_id, const FlutterWindowCreationRequest *request)
FlutterWindowOffset InternalFlutter_Window_GetOffsetInParent(void *window)
int64_t InternalFlutter_WindowController_CreateRegularWindow(int64_t engine_id, const FlutterWindowCreationRequest *request)
void InternalFlutter_Window_SetFullScreen(void *window, bool fullScreen)
void InternalFlutter_Window_UpdatePosition(void *window)
bool InternalFlutter_Window_IsFullScreen(void *window)
void InternalFlutter_Window_SetContentSize(void *window, const FlutterWindowSize *size)
void InternalFlutter_Window_Minimize(void *window)
char * InternalFlutter_Window_GetTitle(void *window)
void InternalFlutter_Window_SetTitle(void *window, const char *title)
bool InternalFlutter_Window_IsMinimized(void *window)
void InternalFlutter_Window_Destroy(int64_t engine_id, void *window)
void InternalFlutter_Window_SetMaximized(void *window, bool maximized)
FlutterWindowSize InternalFlutter_Window_GetContentSize(void *window)
void InternalFlutter_Window_Unminimize(void *window)
NSMutableArray< FlutterWindowOwner * > * _windows
static Isolate Current()
Definition: isolate_scope.cc:9
FlutterMouseTrackingMode mouseTrackingMode
FlutterViewIdentifier viewIdentifier
BOOL sizedToContents
Definition: FlutterView.h:121
void constraintsDidChange()
Definition: FlutterView.mm:200
FlutterViewController * _flutterViewController
FlutterViewController * flutterViewController
std::optional< flutter::Isolate > _isolate
FlutterWindowCreationRequest _creationRequest
struct FlutterWindowConstraints constraints
FlutterWindowRect *(* on_get_window_position)(const FlutterWindowSize &child_size, const FlutterWindowRect &parent_rect, const FlutterWindowRect &output_rect)
static FlutterWindowRect fromNSRect(const NSRect &rect)
static FlutterWindowSize fromNSSize(const NSSize &size)