OSX maximum window height - macos

A window can only be a certain height on OSX. It think this maximum height is: screenheight - menu bar height - title bar height - dock height (only if its visible).
Is there an easy way to get was this value is, or how do you get these values individually? Is this correct?

If You can use Cocoa try visibleFrame method of NSScreen class.
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSScreen_Class/Reference/Reference.html#//apple_ref/occ/instm/NSScreen/visibleFrame

see NSScreen visibleFrame
And screens
Register for and handle
NSApplicationDidChangeScreenParametersNotification
People use multiple displays, external displays and change their display preferences.
You'll also need to decide what to do about the Dock.
You also need to figure out the height when a window spans multiple displays.
Or if it should at a maximum size.
You'll want to consider window restoration handling.
You'll do well to consider handling sleep and wake notifications.
Lastly you'll want to test carefully. This isn't hard but there are a number of dynamics in play that your own setup may not reflect.
One more. Keep in mind that the OS will try to keep a small space for the Dock edge even when the Dock is hiding (left right or bottom) the NSScreen method accounts for this. On Mavericks it seems to be 4 points if I recall correctly.
You can make your app run with the Dock unavailable while your app is active and front. But doing so by API enforcement also hides the menuBar. If you need to do that, either do full screen or consider increasing the window level a lot. ( that's not as rewarding as it sounds but interesting to explore)
Lastly, this stuff changes sometimes in major OS releases. So expect that you may need to accommodate different OS versions.

A window can only be a certain height on OS X.
I could not find a reference to the limits of window sizes, but they are definitely less limited than the current screen size.
Windows can stretch over several (vertically) arranged screens or overlap the menubar and the dock.

Related

How can I make window zooming respect auto layout constraints?

To keep things simple, let's say I have a window containing a single view, which has auto layout constraints binding all 4 sides to the window container view with offset 0. And assume that this view also has a constraint setting its aspect ratio to a constant value. If I resize the window manually, then then window nicely maintains the desired aspect ratio. But if I click the little green zoom widget, then the window fills up the whole screen, regardless of the aspect ratio, with part of the view being above the top of the screen. Is there some way I can make zooming resize the window as big as it can be, without violating auto layout constraints?
I couldn't very well detect this problem in the delegate method windowWillResize:toSize:, because that doesn't tell me which screen it's thinking about putting the window on. I could try to fix the window size in the windowDidResize: delegate method, at which time I do know what screen it's on, but I'm not sure exactly how to do that without reinventing Auto Layout's wheel.
Apparently someone thinks I wasn't explicit enough, so I'll try again. Steps to reproduce:
In Xcode, create a new macOS App project using XIB interface.
Open MainMenu.xib and select the window.
Reshape the window to be approximately square.
Using the Attribute Inspector, set the Full Screen behavior for the window to Auxiliary Window.
Drag an Image View from the library and drop it in the window.
In the Attributes Inspector, set the image view to show the NSComputer image and scale axes independently.
Expand the image view to fill up the window content area.
With the image view selected, click the button to add new layout constraints.
Add 5 constraints, binding the 4 sides to the container, and setting the aspect ratio. (see screen shot)
Build and Run.
Observe that if you resize the window by dragging an edge or corner, the aspect ratio remains fixed.
Click the green zoom widget in the title bar of the window, and observe that the window expands without regard for the aspect ratio constraint, cutting off part of the image.
I just set up a test project exactly as you specified, and when I invoke the window zoom widget, the window expands and retains its aspect ratio i.e. it works as expected. The only thing I can think of that might be causing your issue: maybe your content hugging and content compression resistance priorities are at odds with your constraints? Mind you, I just left them at the default values and it worked fine. Unfortunately Mac/AppKit development (esp. when using IB) is rife with these kind of odd bugs and weird behaviour, probably because Apple has not given it any love in years, so bugs creep in/fester and they are clearly so DONE with developing UI the 'old fashioned way'. (Using SwiftUI to make a Mac app is just as frustrating, in different ways, so I'll stick with what I know). FYI, I used Xcode 13.4.1 to create this test project. Good luck!

Mac/Cocoa: how to determine if a window's screen has menubar and Dock?

Something apparently went wrong with my 1st attempt to ask the question below:
I'm trying to write a legacy fullscreen toggling function that should put a window in or out of fullscreen mode on its current screen (monitor) while leaving the contents of other screens unaffected - regardless of how Spaces are configured.
I've got it working for the "legacy" Spaces mode where each Space spans all attached screens. In that case there's only 1 menubar and Dock, both on the primary screen which can be obtained with [[NSScreen screens] firstObject]. Thus, I can do something like
if ([nsWin screen] == [[NSScreen screens] firstObject]) {
m_normalPresOpts = [nsApp presentationOptions];
[nsApp setPresentationOptions:m_normalPresOpts | NSApplicationPresentationAutoHideMenuBar | NSApplicationPresentationAutoHideDock];
}
to get the Dock and Menubar to auto-hide only when the fullscreen window is on the primary screen.
Apple made it impossible to toggle the Spaces setting without restarting the login session so I do not even know at this point how the above code works when screens have individual Spaces. I suspect though that [[NSScreen screens] firstObject] will then still contain the screen that has its upper-left corner at (0,0) and thus fullscreen windows on other screens will continue to have the menubar and Dock visible. Also, I'm still running 10.9 and would just as well prefer to get this right at once for later versions too.
Is there a way to determine programmatically how Spaces are configured or to know whether a given screen contains the menubar/Dock? Googling didn't give me any results relevant to doing this from code. Somehow I missed [NSScreen +screensHaveSeparateSpaces] in my on-disk documentation, is that the definitive answer to my question?
NSScreen has two properties
frame
This is the full screen rectangle at the current resolution. This rectangle includes any space currently occupied by the menu bar and dock.
visibleFrame
This is the rectangle defining the portion of the screen in which it is currently safe to draw your application content.
The returned rectangle is always based on the current user-interface settings and does not include the area currently occupied by the dock and menu bar. Because it is based on the current user-interface settings, the returned rectangle can change between calls and should not be cached.
Even when dock hiding is enabled, the rectangle returned by this method may be smaller than the full screen. The system uses a small boundary area to determine when it should display the dock.
So, if they are different, than the screen has menubar and/or dock
Is there a way to determine programmatically how Spaces are configured or to know whether a given screen contains the menubar/Dock? Googling didn't give me any results relevant to doing this from code. Somehow I missed [NSScreen +screensHaveSeparateSpaces] in my on-disk documentation, is that the definitive answer to my question?
Yes.
BTW you might have missed it in the documentation if your docs were out of date as this method was introduced as part of the new spaces model without being documented - it only existed in the header file. At some point between then and now the documentation caught up.

How to perfectly mimic toolbar buttons as in Finder, Safari, or other default apps?

I'm trying to create an application that would be as standard as possible in terms of style.
An image is worth a thousand words: I can't figure out how to make my buttons the same size as in Apple's programs such as Safari or Finder.
As you can see, the sizing I've set in interface builder don't seem to match the size the buttons get when I run the app, but maybe that part doesn't speak in pixels but in points or something? Also, textured rounded button has only width editable, but not height.
In this case, these are NSButtons, but I guess I'll have a similar problem with other control types...
I found it out! The problem was with neither of these two parts outlined in the screenshot, but in the "Toolbar" item, higher in the hierarchy.
There is a Size attribute in the Attributes inspector which defaults to Small, but you can set it to Regular instead, and then the buttons get the same sizing as in Finder and all.

Draw NSWindow on one screen only

Let's say we have two screen scenario and a NSWindow,
positioned at the edge of screen 1.
A part of that of that window is also shown on screen 2.
What I would like to achieve, is to draw the window only on screen 1 and to not show the rest on screen 2.
The reason for that is that's some kind of a specially behaving mini window, not a usual one.
Is it possible to assign a certain NSScreen to draw the window on, only?
Two very different approaches:
Use Mavericks: What you looking for sounds like the behaviour of Mavericks' "screens have separate spaces" mode. In this mode a window is never drawn on two screens except during drag operations, at other times the window is draw on one screen with any areas protruding onto adjacent screens clipped. So if you can restrict use to 10.9 this may save you some work.
Borderless Windows: You can create a borderless non-opaque NSWindow, just set the appropriate flags. This is how applications create non-square windows, the visible area of the window is now entirely up to you. Now just clip your drawing to the area on one screen using the standard clipping support. You won't have a standard title bar or controls, unless you emulate them yourself, so you have to implement drag yourself etc. You say you have "some kind of a specially behaving mini window, not a usual one" so that may not be an issue.
Not that I've heard of.
What you could do though is restricting the position of the window e.g. via a NSWindowDelegate and windowDidMove: to listen to position changes and reposition the window appropriately.

Can I change NSScreen visibleframe?

I trying to create a toolbar that docks on the top of the screen below the OS X menu bar.
I would like no other application's to be able to overlap my application when they are maximized. I can get the visible frame dimensions using NSScreen's visibleframe method, but can I adjust the visibleframe to omit the size and position of my application?
The simple answer is that no, you can't. I think that the only way to change the screen's visibleRect would be to inject code into AppKit and swizzle the method.
Even then, it might not do what you want because that method might not be what Apple uses to determine the "safe area" for windows and almost certainly would not work with Carbon apps.
Nothing you do with window levels will change this.
What you could do is use the Accessibility framework to reposition windows if you detect that their frames have changed such that they overlap your toolbar window. Unfortunately, I think you might need use polling for this.
Try setting your window's level to NSDockWindowLevel.
This may not work, depending on whether the system subtracts all windows on that level or only ever the Dock's window, but it's worth a try.

Resources