6 #include <Foundation/Foundation.h>
28 @property(readonly, nonatomic) NSWindow* window;
30 @property(readwrite, nonatomic) BOOL closeWhenParentResignsKey;
32 - (instancetype)initWithWindow:(NSWindow*)window
47 [
self setContentSize:NSMakeSize(contentSize.width, contentSize.height)];
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);
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);
61 [
self setContentMaxSize:NSMakeSize(CGFLOAT_MAX, CGFLOAT_MAX)];
63 if (!NSEqualSizes(originalSize, size)) {
64 [
self setContentSize:size];
83 - (instancetype)initWithWindow:(NSWindow*)window
86 if (
self = [super init]) {
95 - (void)windowDidBecomeKey:(NSNotification*)notification {
96 [_flutterViewController.engine windowDidBecomeKey:_flutterViewController.viewIdentifier];
99 - (void)windowDidResignKey:(NSNotification*)notification {
100 [_flutterViewController.engine windowDidResignKey:_flutterViewController.viewIdentifier];
101 [[_flutterViewController.engine windowController] windowDidResignKey:self];
104 - (BOOL)windowShouldClose:(NSWindow*)sender {
110 - (void)windowWillClose {
114 - (void)windowDidResize:(NSNotification*)notification {
121 - (void)windowDidMiniaturize:(NSNotification*)notification {
128 - (void)windowDidDeminiaturize:(NSNotification*)notification {
133 - (void)windowWillEnterFullScreen:(NSNotification*)notification {
138 - (void)windowWillExitFullScreen:(NSNotification*)notification {
143 - (std::optional<NSSize>)minimumViewSize:(
FlutterView*)view {
152 - (std::optional<NSSize>)maximumViewSize:(
FlutterView*)view {
157 NSSize screenSize =
self.window.screen.visibleFrame.size;
158 double width = screenSize.width;
163 double height = screenSize.height;
168 return NSMakeSize(width, height);
173 static NSRect ComputeGlobalScreenFrame() {
174 NSRect frame = NSZeroRect;
175 for (NSScreen* screen in [NSScreen screens]) {
176 NSRect screenFrame = screen.frame;
177 if (NSIsEmptyRect(frame)) {
180 frame = NSUnionRect(frame, screenFrame);
186 static void FlipRect(NSRect& rect,
const NSRect& globalScreenFrame) {
188 rect.origin.y = (globalScreenFrame.origin.y + globalScreenFrame.size.height) -
189 (rect.origin.y + rect.size.height);
192 - (void)updatePosition {
193 [
self viewDidUpdateContents:self.flutterViewController.flutterView
194 withSize:self.flutterViewController.flutterView.bounds.size];
197 - (void)viewDidUpdateContents:(
FlutterView*)view withSize:(NSSize)newSize {
203 NSRect globalScreenFrame = ComputeGlobalScreenFrame();
206 [
self.window.parentWindow contentRectForFrameRect:self.window.parentWindow.frame];
207 FlipRect(parentRect, globalScreenFrame);
209 NSRect screenRect = [
self.window.screen visibleFrame];
210 FlipRect(screenRect, globalScreenFrame);
217 NSRect positionRect = position->
toNSRect();
218 FlipRect(positionRect, globalScreenFrame);
220 [
self.window setFrame:positionRect display:NO animate:NO];
227 (positionRect.size.width < newSize.width || positionRect.size.height < newSize.height)) {
232 self.window.alphaValue = 1.0;
238 self->_creationRequest.constraints = constraints;
239 [_flutterViewController.flutterView constraintsDidChange];
241 [
self.window flutterSetConstraints:constraints];
252 - (BOOL)canBecomeKeyWindow {
256 - (BOOL)acceptsFirstResponder {
260 - (BOOL)canBecomeMainWindow {
268 - (instancetype)init {
271 _windows = [NSMutableArray array];
281 NSWindow* window = [[NSWindow alloc] init];
284 [window setReleasedWhenClosed:NO];
286 window.contentViewController = controller;
288 NSWindowStyleMaskResizable | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable;
289 window.collectionBehavior = NSWindowCollectionBehaviorFullScreenAuxiliary;
290 if (request->has_size) {
291 [window flutterSetContentSize:request->size];
293 if (request->has_constraints) {
294 [window flutterSetConstraints:request->constraints];
298 flutterViewController:controller
299 creationRequest:*request];
300 window.delegate = owner;
301 [_windows addObject:owner];
303 NSWindow* parent = nil;
305 if (request->parent_view_id != 0) {
313 FML_LOG(WARNING) <<
"Failed to find parent window for ID " << request->parent_view_id;
318 dispatch_async(dispatch_get_main_queue(), ^{
321 [parent beginCriticalSheet:window
322 completionHandler:^(NSModalResponse response){
327 [window setIsVisible:YES];
328 [window makeKeyAndOrderFront:nil];
339 NSWindow* window = [[NSWindow alloc] init];
342 [window setReleasedWhenClosed:NO];
344 window.contentViewController = controller;
345 window.styleMask = NSWindowStyleMaskBorderless;
346 window.hasShadow = NO;
351 flutterViewController:controller
352 creationRequest:*request];
354 controller.flutterView.sizingDelegate = owner;
357 [controller.flutterView constraintsDidChange];
360 window.delegate = owner;
361 [_windows addObject:owner];
363 NSWindow* parent = nil;
365 FML_DCHECK(request->parent_view_id != 0);
373 NSAssert(parent != nil,
@"Tooltip window must have a parent window.");
375 window.ignoresMouseEvents = YES;
376 window.collectionBehavior = NSWindowCollectionBehaviorAuxiliary;
377 [parent addChildWindow:window ordered:NSWindowAbove];
378 window.alphaValue = 0.0;
393 [window setReleasedWhenClosed:NO];
395 window.contentViewController = controller;
396 window.styleMask = NSWindowStyleMaskBorderless;
397 window.hasShadow = NO;
402 flutterViewController:controller
403 creationRequest:*request];
405 controller.flutterView.sizingDelegate = w;
406 [controller.flutterView setBackgroundColor:[NSColor clearColor]];
408 [controller.flutterView constraintsDidChange];
412 [_windows addObject:w];
414 NSWindow* parent = nil;
416 FML_DCHECK(request->parent_view_id != 0);
418 if (owner.flutterViewController.viewIdentifier == request->parent_view_id) {
419 parent = owner.window;
424 NSAssert(parent != nil,
@"Popup window must have a parent window.");
426 window.collectionBehavior = NSWindowCollectionBehaviorAuxiliary;
427 [parent addChildWindow:window ordered:NSWindowAbove];
428 window.alphaValue = 0.0;
437 NSWindow* window = [[NSWindow alloc] init];
440 [window setReleasedWhenClosed:NO];
442 window.contentViewController = controller;
443 window.styleMask = NSWindowStyleMaskResizable | NSWindowStyleMaskTitled |
444 NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
445 if (request->has_size) {
446 [window flutterSetContentSize:request->size];
448 if (request->has_constraints) {
449 [window flutterSetConstraints:request->constraints];
451 [window setIsVisible:YES];
452 [window makeKeyAndOrderFront:nil];
455 flutterViewController:controller
456 creationRequest:*request];
457 window.delegate = owner;
458 [_windows addObject:owner];
463 - (void)destroyWindow:(NSWindow*)window {
466 if (o.window == window) {
472 [_windows removeObject:owner];
473 for (NSWindow* win in owner.
window.sheets) {
474 [
self destroyWindow:win];
477 for (NSWindow* win in owner.
window.childWindows) {
478 [
self destroyWindow:win];
482 [owner.flutterViewController dispose];
483 owner.
window.delegate = nil;
484 [owner.window close];
485 [owner windowWillClose];
491 [owner.flutterViewController dispose];
492 [owner.window close];
494 [_windows removeAllObjects];
497 static BOOL IsChildAncestor(NSWindow* child, NSWindow* ancestor) {
498 NSWindow* current = child.parentWindow;
500 if (current == ancestor) {
503 current = current.parentWindow;
511 if (possibleChild.closeWhenParentResignsKey &&
512 IsChildAncestor(possibleChild.window, parent.window)) {
513 [possibleChild windowShouldClose:possibleChild.window];
526 [engine enableMultiView];
527 return [engine.windowController createRegularWindow:request];
534 [engine enableMultiView];
535 return [engine.windowController createDialogWindow:request];
542 [engine enableMultiView];
543 return [engine.windowController createTooltipWindow:request];
550 [engine enableMultiView];
551 return [engine.windowController createPopupWindow:request];
555 NSWindow* w = (__bridge NSWindow*)window;
557 [engine.windowController destroyWindow:w];
563 return (__bridge
void*)controller.view.window;
567 NSWindow* w = (__bridge NSWindow*)window;
568 NSRect contentRect = [w contentRectForFrameRect:w.frame];
570 .
width = contentRect.size.width,
571 .height = contentRect.size.height,
576 NSWindow* w = (__bridge NSWindow*)window;
577 [w flutterSetContentSize:*size];
583 NSWindow* w = (__bridge NSWindow*)window;
585 [owner setConstraints:*constraints];
589 NSWindow* w = (__bridge NSWindow*)window;
590 w.title = [NSString stringWithUTF8String:title];
594 NSWindow* w = (__bridge NSWindow*)window;
595 if (maximized & !w.isZoomed) {
597 }
else if (!maximized && w.isZoomed) {
603 NSWindow* w = (__bridge NSWindow*)window;
608 NSWindow* w = (__bridge NSWindow*)window;
613 NSWindow* w = (__bridge NSWindow*)window;
614 [w deminiaturize:nil];
618 NSWindow* w = (__bridge NSWindow*)window;
619 return w.isMiniaturized;
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];
633 NSWindow* w = (__bridge NSWindow*)window;
634 return (w.styleMask & NSWindowStyleMaskFullScreen) != 0;
638 NSWindow* w = (__bridge NSWindow*)window;
639 [NSApplication.sharedApplication activateIgnoringOtherApps:YES];
640 [w makeKeyAndOrderFront:nil];
644 NSWindow* w = (__bridge NSWindow*)window;
645 return strdup(w.title.UTF8String);
649 NSWindow* w = (__bridge NSWindow*)window;
650 return w.isKeyWindow;
654 NSWindow* w = (__bridge NSWindow*)window;
656 [owner updatePosition];
660 NSWindow* w = (__bridge NSWindow*)window;
661 NSWindow* parent = w.parentWindow;
665 NSRect globalScreenFrame = ComputeGlobalScreenFrame();
667 NSRect parentRect = [parent contentRectForFrameRect:parent.frame];
668 FlipRect(parentRect, globalScreenFrame);
670 NSRect childRect = w.frame;
671 FlipRect(childRect, globalScreenFrame);
674 .x = childRect.origin.x - parentRect.origin.x,
675 .y = childRect.origin.y - parentRect.origin.y,
#define FLUTTER_DARWIN_EXPORT
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
NSColor * backgroundColor
FlutterMouseTrackingMode mouseTrackingMode
FlutterViewIdentifier viewIdentifier
void constraintsDidChange()
FlutterViewController * _flutterViewController
FlutterViewController * flutterViewController
std::optional< flutter::Isolate > _isolate
CGSize _positionerSizeConstraints
FlutterWindowCreationRequest _creationRequest
BOOL closeWhenParentResignsKey
void(* on_should_close)()
void(* notify_listeners)()
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)