During my recent SubEthaEdit bugfixing efforts I came along some pretty annoying Cocoa Child Window issues.
First a little preamble, why did SubEthaEdit use child windows – this could be filed under “it was a bad idea anyways”. I got the idea searching for a good and safe way of displaying the little SSL-lock icon in the upper right of the window if a connection is SSL-encrypted. Safe meaning a way that wouldn’t break if something fundamental in the way how the window title is displayed would change in the future. Since most of the displaying in the titlebar window area is private API, the results I found when looking around did use some mean subclassing. I didn’t want to do that, so I thought having a tiny transparent child window on top of my window would be a very safe thing to do. So I did. And I was wrong.
Bug number one: Spaces breaks
This seems to be a known issue, when I filed it it almost instantly got duplicated to this one: Child windows and Spaces [rdar://5593261] .
If you have a window with a child window it behaves strangely on spaces. If you open spaces and drag such a window to another screen, then it does not move to the point you dragged it, but to the point it was on the previous screen – much like when you press shift or apple while dragging windows in the spaces view. That in itself wouldn’t be a major problem, but here you go: if you have multiple windows with child windows, all of them gather together on the screen you activate after moving a window around. Hurray, no more spaces for you puny little app :(. So if your app behaves this way, that might be the problem. This was not easy to find out, I found it by chance after making sure that both the main window and child window did have the same collectionBehavior. (P.S.: if you want to put a view in the titlebar, simply ask a standard button for its superview and frame and add some view relative to that. Thanks to Panic for this idea which sounds quite safe too.)
Bug number two: Your app crashes on quit in certain situations
We had this nasty little bug that every now and then crashed SubEthaEdit on quit. Quite an annoying habit, but we did not find a way to reproduce it. Thankfully amongst the many bug reporters who sent us the crash log via the built in reporter, there was one that actually found out a way to reproduce it. The crash only happens if you quit the application while it is in background. Then the child window is somehow overreleased. You can see the setup code of my sample NSDocument here:
This is reproducible both in Leopard and in Tiger and a very bad thing. Not really grasping what goes wrong exactly in that case (if you close the windows or quit normally everything is fine, hence no general memory management problem – update: look at the bottom of the article to see that I was wrong nevertheless) I fixed this one in the 3.0.2 release by changing the lifecycle of the child window. I did so by putting the child window into an instance variable of my window controller subclass, and autorelease it on the dealloc method of it.
What I did not know then was that this didn’t fix it on Tiger in a special occasion: If on Tiger you quit SubEthaEdit while it was not active and had unsaved changes, and then without activating SubEthaEdit first directly click on the “don’t save” button. On PPC-Tiger that is. So I revisited the bug after a bug reporter finally added this magic information of reproducibility. What I did to fix it first was retain all child windows in the AppControllers applicationWillTerminate: delegate method. Which interestingly enough needed me to make an extra class for theses windows to identifiy them, because in the applicationWillTerminate: method the child windows were still alive – the parent windows weren’t. However I finally got rid of all of this by using a different and better method of adding the SSL-ock icon to the window, but some of you that might not be in the luxury of removing their child windows might find my trip valuable.
This one hasn’t been made a duplicate yet and is quite annoying. So if you have the same problem, report a bug referencing this one: Child window overrelease [rdar://5686435] .
If you want to reproduce it, here is my ChildWindow sample I wrote for the bug report. If you want to reproduce the last part of bug number two you have to add an NSWindowController subclass to the sample. Thanks for listening.
I have just been informed by the nice guys at Apple that programatically created windows default to a isReleasedWhenClosed state of YES which explains the overrelease. However why the heck it doesn’t crash when a window is closed does still not seem right to me. And what that means is that if I add the window without autoreleasing or releasing it beforehand that my app leaks windows. Which I verfied using ObjectAlloc – so it is still a bug, but a different one. If you want to do it right you have to setReleaesedWhenClosed:NO on the child window before you add it and everything is fine.