6

How to take notice when an NSWindow is about to be opened or have just opened? That is, the opposite of windowWillClose: delegate method (likewise the opposite of NSWindowWillCloseNotification.)

This is related to this question, but from the other direction.

The background is, I'm looking to couple a window with a tickmark on the main menu (among other things). When the window is shown, the corresponding ̨ menu item should be checked and vice-versa.

Community
  • 1
  • 1
adib
  • 8,285
  • 6
  • 52
  • 91

3 Answers3

4

It should not normally be a mystery when or how a window is made visible. It should only happen in response to something that your own code is doing. If the window is in a NIB and is marked Visible At Launch, then it shows when your code loads that NIB. Otherwise, it should only show if you call one of the -order... methods other than -orderOut: (e.g. -orderFront:) or -makeKeyAndOrderFront:. If the window is controlled by a window controller, then it would show if you invoke -[NSWindowController showWindow:]. Etc.

If you really feel the need to be notified, you can subclass NSWindow and override -orderWindow:relativeTo: and, if orderingMode is not NSWindowOut and the window was not already visible, post a notification of your own.

Ken Thomases
  • 88,520
  • 7
  • 116
  • 154
  • 2
    It could be as a result of window restoration. (Also I would like to know when is the `first` time a window is opened, without needing to subclass the window). – adib Dec 09 '13 at 15:52
  • 3
    For the case of window restoration, you can observe the `NSApplicationDidFinishRestoringWindowsNotification` notification and check if the window is visible. – Ken Thomases Dec 09 '13 at 17:48
  • 6
    Ultimately, the full inventory of ways a window may be made visible serves as evidence in support of the need for a window-will-order-in notification. – Peter Hosey Dec 10 '13 at 18:08
  • There's a large number of possible ways, but only one or two will be used by one's particular code. As I said, it should not be a mystery when or how the window is made visible in any given particular case. – Ken Thomases Dec 10 '13 at 21:34
2

By macOS 10.10, this is somewhat solved by the call to NSViewController's viewWillAppear or viewDidAppear. Have an NSViewController subclass and set it as the contentViewController of the window. Then its viewWillAppear/ viewDidAppear implementation can post a notification that the window will (or did) open.

adib
  • 8,285
  • 6
  • 52
  • 91
  • This will not suffice on its own. The notification is fired each time the window appears, that means also when the application is hidden and then reenabled. – Julian F. Weinert Oct 14 '20 at 16:58
0

You can bind your NSMenuItem value to the NSWindows visible binding Zero lines of code if you do it in IB.

visible: A Boolean value that specifies if the NSWindow is visible.
If visible evaluates to YES, the NSWindow is visible.
Availability: Available in OS X v10.3 and later.

See the NSWindow Binding Documentation for more info.

You can either bind the NSMenuItem value binding to an existing NSWindow property on one of your existing classes, or add an NSObjectController to your nib and set its content to the NSWindow instance then bind to the controller.

Tested and confirmed on Mac OS 10.9. Works for window minimization and restoration too.

Brad Allred
  • 7,323
  • 1
  • 30
  • 49
  • NSWindow doesn't have an `isVisible` property, nor a `visible` property. What it has is an `isVisible` method. It does not guarantee that that method is observable as a KVO-compliant property. – Peter Hosey Dec 09 '13 at 09:14
  • @PeterHosey is does work and _is_ guaranteed by the [binding documentation](https://developer.apple.com/library/mac/documentation/cocoa/reference/CocoaBindingsRef/BindingsText/NSWindow.html) – Brad Allred Dec 09 '13 at 15:39
  • @PeterHosey, the existence of a getter-like method (and `-isVisible` definitely qualifies) is sufficient to establish the existence of a property. **Declared* properties are more explicit/format, but properties existed before that feature was added to the language and run-time. You're right, though, that the mere existence of a property doesn't mean it's KVO-compliant and you must assume a property is not unless it's documented to be. – Ken Thomases Dec 09 '13 at 15:39
  • @KenThomases thanks, of course you guys are technically correct about methods not guaranteeing KVO compliance, however, I have added the documentation for `NSWindow` bindings which shows that `visible` is in fact a viable key for binding. – Brad Allred Dec 09 '13 at 15:41
  • 1
    @BradAllred, the documentation you linked to shows that `NSWindow` has a `visible` binding, but that doesn't mean its "visible" property is KVO-compliant. That documentation is telling you that you can bind `NSWindow`'s "visible" binding *to* a KVO-compliant property and that will cause the window to be shown or hidden as that property changes. – Ken Thomases Dec 09 '13 at 15:41
  • @KenThomases sure, but he can easily accomplish what he wants by adding an `NSObjectController` with its content set to the `NSWindow` instance and binding to the controller. – Brad Allred Dec 09 '13 at 15:49
  • @KenThomases: Yes, `isVisible` can be accessed via KVC (which also pre-dates formal properties), but, as we've agreed, it is not documented as observable using KVO and should not be assumed to be so. – Peter Hosey Dec 09 '13 at 21:03
  • Nothing about an object controller will make the window's `isVisible` method any more of an observable property than it already was. You cannot assume that the window sends KVO notifications for `visible` when the value that `isVisible` would return changes; without such notifications, the property (formal or otherwise) is not observable. Or, more precisely, you can observe it all you want, but you won't get notifications of changes because none were sent. – Peter Hosey Dec 09 '13 at 21:06
  • @PeterHosey all that matters is if binding to `visible` works for the OPs purposes. He specified a desire to have an `NSMenuItem` become checked when an `NSWindow` is visible and unchecked otherwise and this method _does_ work for that, I have tested it. – Brad Allred Dec 09 '13 at 22:08
  • It may work on all OS versions you have tested it on, but won't necessarily work on any before or after (or even in between). It's fragile at best. – Peter Hosey Dec 10 '13 at 00:35
  • @PeterHosey fair enough, its a decision for the OP to make. I've used it for a long time without issue and sometimes a quick easy "undocumented" binding is more palatable than alternatives. – Brad Allred Dec 10 '13 at 13:58
  • I've tried binding the menu item's "value" to the window's "visible" property and found it to be unstable. Perhaps it's because bindings are bi-directional and this is supposed to be uni-directional. It comes across my mind to insert a one-way transformer in the binding, but wonder whether it's worth the complexity. – adib Dec 10 '13 at 14:38
  • @adib yes, I have never used this in a context where the menu item value is updated by anything other than the window binding. I saw in one of your other comments you need to know the first time a window is made visible anyway and this won't help you there anyway. – Brad Allred Dec 10 '13 at 20:52