6#include <Foundation/Foundation.h>
28@property(readonly, nonatomic) NSWindow*
window;
30@property(readwrite, nonatomic)
BOOL closeWhenParentResignsKey;
32- (instancetype)initWithWindow:(NSWindow*)window
38@interface NSWindow (FlutterWindowSizing)
45@implementation NSWindow (FlutterWindowSizing)
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];
80@synthesize window = _window;
83- (instancetype)initWithWindow:(NSWindow*)window
86 if (
self = [super init]) {
89 _creationRequest = creationRequest;
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 {
106 _creationRequest.on_should_close();
110- (void)windowWillClose {
111 _creationRequest.on_will_close();
114- (void)windowDidResize:(NSNotification*)notification {
116 _creationRequest.notify_listeners();
121- (void)windowDidMiniaturize:(NSNotification*)notification {
123 _creationRequest.notify_listeners();
128- (void)windowDidDeminiaturize:(NSNotification*)notification {
130 _creationRequest.notify_listeners();
133- (void)windowWillEnterFullScreen:(NSNotification*)notification {
135 _creationRequest.notify_listeners();
138- (void)windowWillExitFullScreen:(NSNotification*)notification {
140 _creationRequest.notify_listeners();
144 if (_creationRequest.has_constraints) {
145 return NSMakeSize(_creationRequest.constraints.min_width,
146 _creationRequest.constraints.min_height);
153 if (!_creationRequest.has_constraints) {
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);
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);
173static 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);
186static 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 {
198 if (_creationRequest.on_get_window_position ==
nullptr) {
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);
213 auto position = _creationRequest.on_get_window_position(
217 NSRect positionRect = position->toNSRect();
218 FlipRect(positionRect, globalScreenFrame);
220 [
self.window setFrame:positionRect display:NO animate:NO];
226 if (
view.sizedToContents &&
227 (positionRect.size.width < newSize.width || positionRect.size.height < newSize.height)) {
228 _positionerSizeConstraints = positionRect.size;
232 self.window.alphaValue = 1.0;
238 self->_creationRequest.constraints = constraints;
239 [_flutterViewController.flutterView constraintsDidChange];
241 [
self.window flutterSetConstraints:constraints];
249- (instancetype)init {
252 _windows = [NSMutableArray array];
262 NSWindow*
window = [[NSWindow alloc] init];
265 [window setReleasedWhenClosed:NO];
267 window.contentViewController = controller;
269 NSWindowStyleMaskResizable | NSWindowStyleMaskTitled | NSWindowStyleMaskClosable;
270 window.collectionBehavior = NSWindowCollectionBehaviorFullScreenAuxiliary;
272 [window flutterSetContentSize:request->size];
275 [window flutterSetConstraints:request->constraints];
279 flutterViewController:controller
280 creationRequest:*request];
282 [_windows addObject:owner];
284 NSWindow* parent = nil;
299 dispatch_async(dispatch_get_main_queue(), ^{
302 [parent beginCriticalSheet:window
303 completionHandler:^(NSModalResponse response){
308 [window setIsVisible:YES];
309 [window makeKeyAndOrderFront:nil];
320 NSWindow*
window = [[NSWindow alloc] init];
323 [window setReleasedWhenClosed:NO];
325 window.contentViewController = controller;
326 window.styleMask = NSWindowStyleMaskBorderless;
332 flutterViewController:controller
333 creationRequest:*request];
335 controller.flutterView.sizingDelegate = owner;
338 [controller.flutterView constraintsDidChange];
342 [_windows addObject:owner];
344 NSWindow* parent = nil;
355 NSAssert(parent != nil,
@"Tooltip window must have a parent window.");
357 window.ignoresMouseEvents = YES;
358 window.collectionBehavior = NSWindowCollectionBehaviorAuxiliary;
359 [parent addChildWindow:window ordered:NSWindowAbove];
369 NSWindow*
window = [[NSWindow alloc] init];
372 [window setReleasedWhenClosed:NO];
374 window.contentViewController = controller;
375 window.styleMask = NSWindowStyleMaskResizable | NSWindowStyleMaskTitled |
376 NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable;
378 [window flutterSetContentSize:request->size];
381 [window flutterSetConstraints:request->constraints];
383 [window setIsVisible:YES];
384 [window makeKeyAndOrderFront:nil];
387 flutterViewController:controller
388 creationRequest:*request];
390 [_windows addObject:owner];
395- (void)destroyWindow:(NSWindow*)window {
404 [_windows removeObject:owner];
405 for (NSWindow* win in owner.
window.sheets) {
406 [
self destroyWindow:win];
409 for (NSWindow* win in owner.
window.childWindows) {
410 [
self destroyWindow:win];
414 [owner.flutterViewController dispose];
415 owner.
window.delegate = nil;
416 [owner.window close];
417 [owner windowWillClose];
421- (void)closeAllWindows {
423 [owner.flutterViewController dispose];
424 [owner.window close];
426 [_windows removeAllObjects];
429static BOOL IsChildAncestor(NSWindow* child, NSWindow* ancestor) {
430 NSWindow* current = child.parentWindow;
432 if (current == ancestor) {
435 current = current.parentWindow;
443 if (possibleChild.closeWhenParentResignsKey &&
444 IsChildAncestor(possibleChild.window, parent.
window)) {
445 [possibleChild windowShouldClose:possibleChild.window];
458 [engine enableMultiView];
459 return [engine.windowController createRegularWindow:request];
466 [engine enableMultiView];
467 return [engine.windowController createDialogWindow:request];
474 [engine enableMultiView];
475 return [engine.windowController createTooltipWindow:request];
479 NSWindow* w = (__bridge NSWindow*)
window;
481 [engine.windowController destroyWindow:w];
487 return (__bridge
void*)controller.view.window;
491 NSWindow* w = (__bridge NSWindow*)
window;
492 NSRect contentRect = [w contentRectForFrameRect:w.frame];
494 .
width = contentRect.size.width,
495 .height = contentRect.size.height,
500 NSWindow* w = (__bridge NSWindow*)
window;
501 [w flutterSetContentSize:*size];
507 NSWindow* w = (__bridge NSWindow*)
window;
509 [owner setConstraints:*constraints];
513 NSWindow* w = (__bridge NSWindow*)
window;
514 w.title = [NSString stringWithUTF8String:title];
518 NSWindow* w = (__bridge NSWindow*)
window;
519 if (maximized & !w.isZoomed) {
521 }
else if (!maximized && w.isZoomed) {
527 NSWindow* w = (__bridge NSWindow*)
window;
532 NSWindow* w = (__bridge NSWindow*)
window;
537 NSWindow* w = (__bridge NSWindow*)
window;
538 [w deminiaturize:nil];
542 NSWindow* w = (__bridge NSWindow*)
window;
543 return w.isMiniaturized;
547 NSWindow* w = (__bridge NSWindow*)
window;
548 bool isFullScreen = (w.styleMask & NSWindowStyleMaskFullScreen) != 0;
549 if (fullScreen && !isFullScreen) {
550 [w toggleFullScreen:nil];
551 }
else if (!fullScreen && isFullScreen) {
552 [w toggleFullScreen:nil];
557 NSWindow* w = (__bridge NSWindow*)
window;
558 return (w.styleMask & NSWindowStyleMaskFullScreen) != 0;
562 NSWindow* w = (__bridge NSWindow*)
window;
563 [NSApplication.sharedApplication activateIgnoringOtherApps:YES];
564 [w makeKeyAndOrderFront:nil];
568 NSWindow* w = (__bridge NSWindow*)
window;
569 return strdup(w.title.UTF8String);
573 NSWindow* w = (__bridge NSWindow*)
window;
574 return w.isKeyWindow;
578 NSWindow* w = (__bridge NSWindow*)
window;
580 [owner updatePosition];
#define FLUTTER_DARWIN_EXPORT
void InternalFlutter_Window_Activate(void *window)
bool InternalFlutter_Window_IsMaximized(void *window)
int64_t InternalFlutter_WindowController_CreateTooltipWindow(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)
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)
void * InternalFlutter_Window_GetHandle(int64_t engine_id, FlutterViewIdentifier view_id)
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)
char * InternalFlutter_Window_GetTitle(void *window)
FlutterWindowSize InternalFlutter_Window_GetContentSize(void *window)
void InternalFlutter_Window_Unminimize(void *window)
NSMutableArray< FlutterWindowOwner * > * _windows
G_BEGIN_DECLS FlutterViewId view_id
#define FML_LOG(severity)
NSColor * backgroundColor
FlutterViewIdentifier viewIdentifier
void constraintsDidChange()
FlutterViewController * _flutterViewController
FlutterViewController * flutterViewController
std::optional< flutter::Isolate > _isolate
CGSize _positionerSizeConstraints
FlutterWindowCreationRequest _creationRequest
BOOL closeWhenParentResignsKey
FlutterViewController * viewController
static FlutterWindowRect fromNSRect(const NSRect &rect)
static FlutterWindowSize fromNSSize(const NSSize &size)