3
votes

I have a super strange problem. I want a Textured window to have it normal gradient color. I have an NSTextField in this window, the text field is destined to be an URL input field so it need to be large. The problem is that when it is too large (approximately more than 1/3 of the window width) it just switch the textured window to draw a darker version of it gradient.

Here is an example project (very simple...) for you to test.

http://raven.ipodtutofast.com/test.zip

When you will build and run it notice the background of the window, initial one is fine, now make the window bigger, it will switch to a darker background.

I really don't have any idea on how to fix this.

Update: Thanks to cocoahero, if in the content border setting in IB you choose custom you can just set the gradient height to whatever you want, never noticed that before.

2

2 Answers

11
votes

It appears to be related to the windows "content border" setting. When it is set to none in IB, the problem doesn't occur, but also modifies the gradient. Seems like a bug to me. Perhaps time for a radar?

4
votes

I also experienced the gradient issue noted above on textured NSWindows in my application, but it took me a long time to find this post which helped solve the issue.

I wished to add a little more to this posting so if other developers find they are experiencing the same issue that the solution may come to light more easily in future.

In my case, I had built an application with a set of textured windows. Similarly to Dimillian77's issue, my application's main window background texture was being affected by the sizing and placement of sub-views, in my case, these were the various NSView sub-views that the main window's NSWindowController switches in/out according to which area of the application the user is accessing. As the sizing and placement of the NSView sub-views differs slightly for each sub-view, this accordingly made the gradient bug more obvious when users switched between each view, as the main window's background gradient would jump around behind the sub-view.

Interestingly the gradient issue only appeared after making the transition to OS X 10.7 Snow Leopard – the same, unmodified source code and .xib/.nib files did not result in this issue on any earlier versions of OS X. This would seem to concur with cocoahero's suggestion that this issue may be a new bug worthy of a Radar report – perhaps we will find it has been fixed in Mountain Lion?

As it was, the main NSWindow of my application and several supporting windows were all set to use the "Textured" (metallic) background option, but only after the move to Snow Leopard did the gradient 'bug' manifest.

Prior to finding this post, the only way I had stumbled upon to 'solve' the issue was in noticing that if the window had its "Resize" control enabled that the gradient bug disappeared!

However, I did not want my particular application windows to be resizable, and as much as I could disable the title bar "Resize" control with -(void)setShowsResizeIndicator:(BOOL)showResizeIndicator, and override attempts by the user to resize the window by intercepting calls to -(NSSize)windowWillResize:(NSWindow *)sender toSize:(NSSize)frameSize, this clearly wasn't an elegant solution or the way to go. This solution failed particularly as the window still exhibited its resize mouse cursors (which I had not been able to hide), as these were confusing to users as I was overriding any attempts to resize the window in code.

Thankfully, cocoahero's solution of changing the "Content Border" setting to "None", immediately made the gradient issue disappear in Interface Builder (the version integrated with Xcode 4.3.3), but at least in my case, when initially compiling and running the application after making this change, the application crashed as soon as the .xib files were loaded. The following error message appeared in the trace: "setAutorecalculatesContentBorderThickness:forEdge: may not be called with NSMaxYEdge in a non-textured window".

I found that setting the "Content Border" setting to "Custom" and setting the "Top" and "Bottom" content borders to "1" solved the crash, although strangely after saving and compiling the application with the "Custom" setting in place, I found through experimentation that I was then able to change the "Custom Border" setting to "None" and compile the application and have it run normally on the second compilation.

However, changing the "Content Border" to anything other than "Autosize" resulted in dozens of "Illegal Configuration: Auto Layout on Mac OS X prior to 10.7" errors in XCode, as well as a number of "Attribute Unavailable: Values other than Autosize for Top/Bottom Content Border property on Mac OS X versions prior to 10.6" errors – all related to the the "Content Border" property (my deployment target is set to OS X 10.6 rather than 10.7). Thus the search for another solution to the error resumed, which led me to the solution detailed below. The solution I found, at least on OS X 10.7, was to set the "Content Border" of each textured window back to "Autosize" in Interface Builder and to instead override the content border settings in code (in my case by placing this code into each of my textured window's NSWindowController classes):

// windowDidLoad is called when the window has loaded but before it's displayed...
-(void)windowDidLoad
{
    // set the content border thickness to 0 for both the top and bottom window edges
    [[super window] setContentBorderThickness:0 forEdge:NSMaxYEdge]; // top border
    [[super window] setContentBorderThickness:0 forEdge:NSMinYEdge]; // bottom border

    // disable the auto-recalculation of the window's content border
    [[super window] setAutorecalculatesContentBorderThickness:NO forEdge:NSMaxYEdge];
    [[super window] setAutorecalculatesContentBorderThickness:NO forEdge:NSMinYEdge];
}

Please note that you can only set the top content border thickness on textured windows, if you try to set it either through code or through interface builder on other NSWindow types, the system will raise an exception, likely resulting in an application crash.

According to the NSWindow docs: "In a non-textured window calling setContentBorderThickness:forEdge: passing NSMaxYEdge will raise an exception. It is only valid to set the content border thickness of the top edge in a textured window."

As the gradient issue does indeed seem to be a new bug in OS X 10.7's rendering of "Textured" windows, it may be wise to modify any code that overrides content borders so that such code is only executed on systems running OS X 10.7 (and possibly future OS X releases if the issue remains unfixed in Mountain Lion).

I hope this post is useful, this bug was truly confounding, and took much longer than I had hoped to solve. As there seems to be such sparse documentation of the issue, I felt it was worth the time to post my findings in the hopes that it saves others time and hopefully gives the issue more exposure and keywords to be found with through online search.

Thanks must go to cocoahero, as without their answer, I and many others would still be struggling to solve this issue.