Disable maximise button on macOS?

How does one disable the maximise/fullscreen behavior on macOS?

My main window ctor looks like:

MainWindow::MainWindow (String name)
:  DocumentWindow (name, Colours::grey, 0)
{
}

…but my title bar still has the maximis(z)e button active:

buttons

On Windows, things behave as I’d expect, but under macOS, I can’t find a way to disable this behavior – there are resize limits specified for the app that are being ignored here (I’m assuming because setBounds() is being called directly, which I know isn’t affected by resize limits).

1 Like

FWIW, I’ve been having the same problem and would also like to know.

I might be mistaken, but I think you gotta set the flag directly on the Component Peer instance.

Correct, the ComponentPeer::StyleFlags are defined for the ComponentPeer.

But you can set them, when you put your window to the desktop, when you called Component::addToDesktop (int windowStyleFlags, void* nativeWindowToAttachTo = nullptr)

Adding: if you use the DocumentWindow, there is another enum flag in the constructor specifically for which buttons to use:

requiredButtons
specifies which of the buttons (close, minimise, maximise) should be shown on the title bar. This value is a bitwise combination of values from the TitleBarButtons enum.
Note that it can be “allButtons” to get them all. You can change this later with the setTitleBarButtonsRequired() method, which can also specify where they are positioned.

Right, that’s my puzzlement – I’m setting the style flags here to zero, which on Windows successfully disables all three buttons. On macOS, I’ve stepped down into the guts of the ComponentPeer code for macOS, and it looks like the maximise flag is completely ignored?

static unsigned int getNSWindowStyleMask (const int flags) noexcept
{
    unsigned int style = (flags & windowHasTitleBar) != 0 ? NSWindowStyleMaskTitled
                                                          : NSWindowStyleMaskBorderless;

    if ((flags & windowHasMinimiseButton) != 0)  style |= NSWindowStyleMaskMiniaturizable;
    if ((flags & windowHasCloseButton) != 0)     style |= NSWindowStyleMaskClosable;
    if ((flags & windowIsResizable) != 0)        style |= NSWindowStyleMaskResizable;
    return style;
}

…so we go more deeply into the component peer code to the point where we’re creating and initializing the NSWindow that our component uses, and looking up the valid values of NSWindowStyleMask on the Apple developer website, we note that there’s no style flag present to affect this fullscreen/maximize behavior, so not a JUCE problem, a macOS design that makes me harrumph.

Since my app is designed to have a maximum size, I guess that the approach to take here is:

  1. When we’re on the mac
  2. In my main component’s paint() method, look to see if the local bounds are larger than the current max size as set by the last call to setResizeLimits()
  3. If so, fill the bounds in a bg color, and then make sure that my component is actually drawn into a new rect at the maximum size, centered within the window bounds.

Better ideas (not including ‘redesign the UI to work at arbitrary sizes’), anyone?

1 Like

The buttons on the Window’s title bar are actually accessible through some Objective-c code. I have a routine which show/hides those buttons.
The void* view pointer is retrieved by calling getPeer()->getNativeHandle().

void OSXUIUtils::showHideWindowButtons(void* view, bool show, bool animate, float duration)
{
	NSView* nsView = (NSView*)view;
	NSWindow* nsWindow = [nsView window];
	
//[nsWindow setWindowController:(__kindof NSWindowController * _Nullable)

	CGFloat alpha = show ? 1.0 : 0.0;
	if (animate)
	{
		[NSAnimationContext beginGrouping];
		[[NSAnimationContext currentContext] setDuration:duration];
		[[[nsWindow standardWindowButton:NSWindowMiniaturizeButton] animator]  setAlphaValue:alpha];
		[[[nsWindow standardWindowButton:NSWindowZoomButton] animator]  setAlphaValue:alpha];
		[[[nsWindow standardWindowButton:NSWindowCloseButton] animator]  setAlphaValue:alpha];
		[NSAnimationContext endGrouping];
	} else {
		[[nsWindow standardWindowButton:NSWindowMiniaturizeButton] setAlphaValue:alpha];
		[[nsWindow standardWindowButton:NSWindowZoomButton] setAlphaValue:alpha];
		[[nsWindow standardWindowButton:NSWindowCloseButton] setAlphaValue:alpha];
	}
}

Or something like this:

void OSXUIUtils::hideFullscreenButton(void* view)
{
	NSView* nsView = (NSView*)view;
	NSWindow* nsWindow = [nsView window];
	NSButton *button = [nsWindow standardWindowButton:NSWindowFullScreenButton];
	[button setHidden:YES];
	button.alphaValue = 0.0;
	[button setEnabled:NO];
	button.image = nil;
	button.alternateImage = nil;
}
1 Like

Wow, thanks. I’ll dig into this.

I mean, shouldn’t this “just work” in JUCE without a native workaround? It sounds like a big bug or oversight for some of the desktop option flags to simply not work

3 Likes

I’m doing something like this. Think it works.

 MainWindow::MainWindow() : DocumentWindow(name, Colours::grey, DocumentWindow::TitleBarButtons::closeButton | DocumentWindow::TitleBarButtons::minimiseButton)

Hi, this bug still seems to be present. I’m trying to disable the maximise button in my MacOS app, but the following leaves all three showing:
MainWindow::MainWindow() : DocumentWindow(..., ..., DocumentWindow::TitleBarButtons::minimiseButton | DocumentWindow::TitleBarButtons::closeButton)

Including just DocumentWindow::TitleBarButtons::closeButton hides the minimise button only, and vice versa, so it seems the maximise flag is the only problem.

The same happens if I use setTitleBarButtonsRequired() in the constructor.

Yup still having the same problem here in macOS, and for a DocumentWindow that I definitely don’t want to allow to be maximized.

Calling this in the DocumentWindow constructor still results in a window with the maximize button in the title-bar:

setTitleBarButtonsRequired (0, true);

Additionally, the maximiseButtonPressed callback is being ignored (as reported here as well) - so I’m not able to disable the maximize action.

ref: setTitleBarButtonsRequired, maximiseButtonPressed

Any of the JUCE devs gotten to take a look at this?

I’ve updated the behaviour a bit here:

The ‘zoom’ button will now be disabled for non-resizable windows. The ‘maximize’ flag for the document window now controls whether the window is able to enter true full-screen mode.

In testing, this seemed a lot more intuitive than the current behaviour. Hopefully you’ll agree!

1 Like

Thank you @reuk, that is huge improvement in window behavior. Just tested those changes out here. Blocking full-screen mode is a sufficient fix for my purposes.

I’ll mention two things that might still be patched up a bit, though neither one is pressing for me:

  1. The docs for DocumentWindow::setTitleBarButtonsRequired say the requiredButtons flags will determine which buttons will be shown on the title bar. Since this is not the actual behavior (on macOS anyways) maybe that could be amended.

  2. The maximiseButtonPressed callback is still not getting called, regardless of the setting of the maximize flag.

It’s not clear to me that it should be called in this case. It doesn’t seem to be called on other platforms when using native titlebars.