Unresponsive UI Elements after closing NSWindow - macos

Last week I spent a good amount of time fiddling around with the following problem. I solved it but since I couldn't find an answer here and I want to share my solution for anybody who runs into this.
Problem: My application runs in the background (menubar) and its main NSWindow contains all the preferences of my application. You close the NSWindow by clicking the close button in the top-left. After closing the NSWindow and reopening it, all the NSControls were not visually responding. The actions worked accordingly, but they where not updating.
I tried the following:
Unchecking "Release on close" in IB for NSWindow
Reloading NSWindow from NIB
Strong references for all NSControls
Calling "Become first responder" on NSControls
Reloading all the parenting NSViews
Implementing all the delegates hooking up each NSControl (Worked for NSControl, but was way too much work to use it for each and every one)
Disabling and then reenabling the NSControls
I'll post my solution below for the records.

My solution to this problem was to subclass NSWindow and overwrite the following methods:
- (void)performClose:(id)sender{
[self orderOut:nil];
}
- (void)close{
[self orderOut:nil];
}
Now the NSWindow is hidden / ordered out and you just have to order it back in when displaying it.

Related

NSWindowController displays nib before windowDidLoad finishes

When I try launching my app through Spotlight without building it through XCode, the NSWindowController displays the unmodified nib (with the standard gray background color, etc) for a split second before windowDidLoad finishes. This looks awful, since views are in the wrong places and aren't colored correctly.
I tried removing everything from windowDidLoad to see if something in there was slowing it down, but that didn't improve things. I also tried moving the setting of the background color to initWithWindowNibName, but that didn't help either.
Is there a way to delay showing the window while it finishes loading?
Here's the code I'm using to initialize the NSWindowController:
self.windowController = [[WindowController alloc] initWithWindowNibName:#"WindowController"];
[self.windowController showWindow:self];
[[self.windowController window] makeKeyAndOrderFront:nil];
Disable NSWindowController's "visible at launch" property in Interface Builder.
(Of course, I post the question then immediately figure out the answer.)

adding delegate to responder chain stops scrolling from working

For a number of reasons, I have added my class that implements NSOutlineViewDelegate protocol to the responder chain:
[myOutlineView setNextResponder:self];
This stops my outline view from scrolling. Take the call out - scrolling works fine, put it back - scrolling stops. If I use the up and down arrows to move the selection through the view it scrolls to show the selected row OK, but gesture scrolling doesn't do anything.
The delegate contains quite a few methods for supporting drag and drop, and ibaction methods for supporting context menus, but I can't think what is in there that would interfere with scrolling (I am using a macbook air with gesture scrolling). Anyone got any ideas what is causing the interference? or any ideas how to diagnose?
I should add that I made the delegate class a subclass of NSResponder.
So the answer is, when adding a delegate into the responder chain, you must also add to the delegate the responder that used to be in its place - otherwise the chain gets broken and the events don't get handled, so it goes:
NSResponder *nextResponder = myOutlineView.nextResponder;
[myOutlineView setNextResponder:self];
[self setNextResponder:nextResponder];
With the responder chain restored, my outline view now scrolls again. Hooray

When WebView is added to a specific view in NSWindow, :hover stops working. How can I fix this?

If I create a WebView and add it to NSThemeFrame like so:
Let window be the NSWindow instance I'm adding to:
NSView * themeFrame = window.contentView;
[themeFrame.superview addSubview:myWebView];
Then any :hover tags of elements in the page I load doesn't work anymore. However, the :hover does appear on mouseDown/mouseUp. So maybe this is a refresh issue. I tried calling [myWebView setNeedsDisplay:YES] in mouseMoved: but no luck.
Is there something special about contentView? I tried the same thing with an NSView and overrode its mouseMoved: method while calling setNeedsDisplay and the NSView handled mouseMove fine. Is there something special about :hover?
Any ideas or ramblings are welcome!
I might have the same problem as Cocoa WebView on os X not firing mouse hover events without having to click and hold left mouse key but there's no answer there.
I had a similar problem and after debugging and reading the source of WebKit, I found a solution. The crucial part seems to the WebHTMLView class, specifically the method -[WebHTMLView _updateMouseoverWithEvent:]. There's a check whether the view's window is a key window and sure enough, my window wasn't key even though I called makeKeyWindow on it.
My window was a child window of a document window and to solve the hover issue, I created a NSWindow subclass and overrode isKeyWindow like this:
- (BOOL)isKeyWindow
{
return [super isKeyWindow] || [[self parentWindow] isKeyWindow];
}
This made hover work in WebView in my document's child window.

NSOutlineView - scroll to top at launch

Got an NSOutlineView that is configured in the controller's awakeFromNib, with a datasource and autosaved expanded nodes.
All working like a charm.
The problem is that somewhere, somebody is saving the state of the scroll position, too.
This means that at launch of the app, the outline view can appear scrolled to the bottom - if that was how the user left it last (this is on Lion if it matters).
What is the best way to open the app with the outline view scrolled to the top? Preferably in awakeFromNib, or at least so the user won't be seeing a scroll movement.
I recently started having problems with my NSOutlineView being scrolled down (so that I couldn't see my elements until I scrolled up), and I used this method :
In my applicationDidLaunch: method I use this :
[outlineView scrollPoint:NSMakePoint(0.0f, [outlineView frame].size.height)];
And it seems to work. (I also had the same problem on an IKImageBrowserView, and the same piece of code worked on that too)
Hope this solution suites you better ^^
What about [outlineView scrollToVisible:0]; ?

Display NSWindow as Subview of NSView

I have an NSWindow that I want to display as part of another window. It has to be an NSWindow; I don't want to change it to an NSView or anything... I just don't because it involves accessing foreign nib files and the such.
How should I accomplish this if possible? I was thinking along the lines of grabbing the view of the NSWindow and sticking it as the subview of another view in my main window... but I don't think this is possible. Is it?
If you're okay with the window as-is, just add it as a child window to the window in your own app. That will handle positioning and everything, although you might have to patch up the responder chain and such to really get things working properly.

Resources