Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -221,21 +221,44 @@ - (void)_setResizable:(bool)resizable
}

NSUInteger mask = [self->nsWindow styleMask];
BOOL isPopupOrUtility = (mask & NSWindowStyleMaskUtilityWindow) != 0 || (mask & NSWindowStyleMaskNonactivatingPanel) != 0;

if (resizable) {
mask |= NSWindowStyleMaskResizable;
[self->nsWindow setStyleMask: mask];
[self->nsWindow setShowsResizeIndicator:YES];

NSButton *zoomButton = [self->nsWindow standardWindowButton:NSWindowZoomButton];
[zoomButton setEnabled:YES];

// When window becomes resizable, ownerless window gets the Full Screen Toggle control
if (!self->owner && !isPopupOrUtility) {
NSWindowCollectionBehavior behavior = [self->nsWindow collectionBehavior];
behavior |= NSWindowCollectionBehaviorFullScreenPrimary;
[self->nsWindow setCollectionBehavior: behavior];
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is minor but I've never understood the coding conventions in the Mac glass code. I have no idea why there's all the references to self and why no one uses property notation. In any other codebase this line would just be

nsWindow.collectionBehavior = behavior;

I wouldn't change anything in this PR since it does follow the prevailing conventions but I urge anyone writing new code to at least drop all the self references.

}
} else {
// Disable zoom button immediately to provide visual feedback
[[self->nsWindow standardWindowButton:NSWindowZoomButton] setEnabled:NO];

// If window is currently in full screen, exit fullscreen mode immediately
BOOL isInFullScreen = (mask & NSWindowStyleMaskFullScreen) != 0;
if (isInFullScreen) {
[self->nsWindow toggleFullScreen:nil];
// Defer style mask changes to windowDidExitFullScreen, when fullscreen exit animation completes
return;
}

mask &= ~(NSUInteger)NSWindowStyleMaskResizable;
[self->nsWindow setStyleMask: mask];
[self->nsWindow setShowsResizeIndicator:NO];

NSButton *zoomButton = [self->nsWindow standardWindowButton:NSWindowZoomButton];
[zoomButton setEnabled:NO];
// When window becomes non-resizable, remove behavior to prevent access to fullscreen/Mission Control, unless
// is is a borderless window
BOOL isTitled = (mask & NSWindowStyleMaskTitled) != 0;
if (!self->owner && !isPopupOrUtility && isTitled) {
NSWindowCollectionBehavior behavior = [self->nsWindow collectionBehavior];
behavior &= ~NSWindowCollectionBehaviorFullScreenPrimary;
[self->nsWindow setCollectionBehavior: behavior];
}
Comment thread
jperedadnr marked this conversation as resolved.
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -287,13 +287,59 @@ - (void)windowDidExitFullScreen:(NSNotification *)notification
GlassViewDelegate* delegate = (GlassViewDelegate*)[self->view delegate];
[delegate setResizableForFullscreen:self->isWindowResizable];

// Recalculate the style mask to restore miniaturizable and resizable states
NSUInteger currentMask = [self->nsWindow styleMask];
NSUInteger managedBits = (NSUInteger)(NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable);
NSUInteger newMask = (currentMask & ~managedBits);

// Restore miniaturizable from saved state
if (self->enabledStyleMask & NSWindowStyleMaskMiniaturizable) {
newMask |= NSWindowStyleMaskMiniaturizable;
}
// And set resizable based on current isResizable flag
if (self->isResizable) {
newMask |= NSWindowStyleMaskResizable;
}
[self->nsWindow setStyleMask: newMask];

// Apply collection behavior changes that were deferred from _setResizable
BOOL isPopupOrUtility = (newMask & NSWindowStyleMaskUtilityWindow) != 0 || (newMask & NSWindowStyleMaskNonactivatingPanel) != 0;
BOOL isTitled = (newMask & NSWindowStyleMaskTitled) != 0;
if (!self->owner && !isPopupOrUtility) {
NSWindowCollectionBehavior behavior = [self->nsWindow collectionBehavior];
if (self->isResizable || !isTitled) {
behavior |= NSWindowCollectionBehaviorFullScreenPrimary;
} else {
behavior &= ~NSWindowCollectionBehaviorFullScreenPrimary;
}
[self->nsWindow setCollectionBehavior: behavior];
}

// Update button states based on current window state after style mask is applied
BOOL isWindowEnabled = self->isEnabled;
BOOL isMiniaturizable = ([self->nsWindow styleMask] & NSWindowStyleMaskMiniaturizable) != 0;
[[self->nsWindow standardWindowButton:NSWindowCloseButton] setEnabled: isWindowEnabled];
[[self->nsWindow standardWindowButton:NSWindowMiniaturizeButton] setEnabled: isWindowEnabled && isMiniaturizable];
[[self->nsWindow standardWindowButton:NSWindowZoomButton] setEnabled: isWindowEnabled && self->isResizable];

[delegate sendJavaFullScreenEvent:NO withNativeWidget:YES];
[GlassApplication leaveFullScreenExitingLoopIfNeeded];

// Fix up window stacking order
[self reorderChildWindows];
}

- (void)windowDidFailToExitFullScreen:(NSNotification *)notification
{
//NSLog(@"windowDidFailToExitFullScreen");

// Fullscreen exit failed - window remains in fullscreen mode, restore buttons
BOOL isWindowEnabled = self->isEnabled;
[[self->nsWindow standardWindowButton:NSWindowCloseButton] setEnabled:isWindowEnabled];
[[self->nsWindow standardWindowButton:NSWindowMiniaturizeButton] setEnabled: NO];
[[self->nsWindow standardWindowButton:NSWindowZoomButton] setEnabled: isWindowEnabled && self->isResizable];
}

- (BOOL)windowShouldClose:(NSNotification *)notification
{
if (self->isEnabled)
Expand Down
78 changes: 60 additions & 18 deletions modules/javafx.graphics/src/main/native-glass/mac/GlassWindow.m
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2011, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2011, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
Expand Down Expand Up @@ -127,7 +127,6 @@ - (id)initWithDelegate:(GlassWindow*)delegate
\
[self setDelegate:delegate]; \
[self setAcceptsMouseMovedEvents:NO]; \
[self setShowsResizeIndicator:NO]; \
[self setAllowsConcurrentViewDrawing:YES]; \
\
[self setReleasedWhenClosed:YES]; \
Expand Down Expand Up @@ -567,8 +566,14 @@ static jlong _createWindowCommonDo(JNIEnv *env, jobject jWindow, jlong jOwnerPtr
NSWindowCollectionBehavior behavior = [window->nsWindow collectionBehavior];
if (!isPopup && !isUtility && !window->owner)
{
// Only ownerless windows should have the Full Screen Toggle control
behavior |= (1 << 7) /* NSWindowCollectionBehaviorFullScreenPrimary */;
// Only resizable ownerless windows should have the Full Screen Toggle control
// This behavior is applied later in _setResizable:YES when the window becomes resizable.

// Non-resizable ownerless windows keep the default behavior, which doesn't allow full screen access,
// except if they are undecorated/borderless windows:
if (!isTitled) {
behavior |= NSWindowCollectionBehaviorFullScreenPrimary;
}
}
else
{
Expand Down Expand Up @@ -597,6 +602,10 @@ static jlong _createWindowCommonDo(JNIEnv *env, jobject jWindow, jlong jOwnerPtr
window->isSizeAssigned = NO;
window->isLocationAssigned = NO;
window->isResizable = NO;

// Initialize enabledStyleMask with current miniaturizable and resizable bits
window->enabledStyleMask = [window->nsWindow styleMask] & (NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable);

[window _setResizable:NO]; // actual value will be set later with a separate JNI downcall
[window->nsWindow setAppearance:isDarkFrame
? [NSAppearance appearanceNamed:NSAppearanceNameDarkAqua]
Expand Down Expand Up @@ -820,23 +829,56 @@ static jlong _createWindowCommonDo(JNIEnv *env, jobject jWindow, jlong jOwnerPtr
{
GlassWindow *window = getGlassWindow(env, jPtr);
window->isEnabled = (BOOL)isEnabled;

NSUInteger mask = [window->nsWindow styleMask];
BOOL isInFullScreen = (mask & NSWindowStyleMaskFullScreen) != 0;
BOOL isPopupOrUtility = (mask & NSWindowStyleMaskUtilityWindow) != 0 || (mask & NSWindowStyleMaskNonactivatingPanel) != 0;
BOOL isRegularWindow = !window->owner && !isPopupOrUtility;
NSUInteger managedBits = (NSUInteger)(NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable);

NSButton *closeButton = [window->nsWindow standardWindowButton:NSWindowCloseButton];
NSButton *zoomButton = [window->nsWindow standardWindowButton:NSWindowZoomButton];
if ((window->isEnabled) && (window->isResizable)){
[window->nsWindow setStyleMask: window->enabledStyleMask];
if (window->enabledStyleMask & NSWindowStyleMaskResizable) {

if ((window->isEnabled) && (window->isResizable)) {
// Restore miniaturizable and resizable styles, if not in fullscreen and is a regular window
if (!isInFullScreen && isRegularWindow) {
[window->nsWindow setStyleMask: (mask & ~managedBits) | window->enabledStyleMask];
}
// Restore zoom button state
if (zoomButton != nil) {
[zoomButton setEnabled:YES];
}
}
else if((window->isEnabled) && (!window->isResizable)){
[window->nsWindow setStyleMask:
(window->enabledStyleMask & ~(NSUInteger) NSWindowStyleMaskResizable)];
[zoomButton setEnabled:NO];
}
else{
window->enabledStyleMask = [window->nsWindow styleMask];
[window->nsWindow setStyleMask:
(window->enabledStyleMask & ~(NSUInteger)(NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable))];
[zoomButton setEnabled:NO];
// Enable close button as window is re-enabled
if (closeButton != nil) {
[closeButton setEnabled:YES];
}
} else if ((window->isEnabled) && (!window->isResizable)) {
// Restore miniaturizable style, clear resizable style, if not in fullscreen and is a regular window
if (!isInFullScreen && isRegularWindow) {
[window->nsWindow setStyleMask:
(mask & ~managedBits) | (window->enabledStyleMask & ~(NSUInteger) NSWindowStyleMaskResizable)];
}
// Disable zoom button as window is not resizable
if (zoomButton != nil) {
[zoomButton setEnabled:NO];
}
// Enable close button as window is re-enabled
if (closeButton != nil) {
[closeButton setEnabled:YES];
}
} else {
// Disabling the window - save both miniaturizable and resizable bits, if not in fullscreen and is a regular window
if (!isInFullScreen && isRegularWindow) {
window->enabledStyleMask = mask & managedBits;
[window->nsWindow setStyleMask: mask & ~managedBits];
}
// Disable both zoom and close buttons as window is disabled
if (zoomButton != nil) {
[zoomButton setEnabled:NO];
}
if (closeButton != nil) {
[closeButton setEnabled:NO];
}
Comment thread
jperedadnr marked this conversation as resolved.
}
}
GLASS_POOL_EXIT;
Expand Down