How to catch the plugin window focus loss event in mac OS?

I made a drop-down list of presets with the ability to specify favorites.

image

It closes when you select a preset, or by clicking the mouse to any other place in the plugin window. I would also like the list to close also when the focus of the plugin window is lost. If in Windows this is solved by reacting to the WM_KILLFOCUS message, then in mac OS, unfortunately, I do not know how to implement it.
I would appreciate any help on this issue.

However, not everything turned out as well as we would like. I had to add the code to some files:

  1. IGraphicsMac_view.h:
@interface IGRAPHICS_VIEW : NSView <NSTextFieldDelegate/*, WKScriptMessageHandler*/>
{
  ...
}
- (void) windowDidResign: (NSNotification*)notification;
- (BOOL) resignFirstResponder;
  1. IGraphicsMac_view.mm:
- (void) viewDidMoveToWindow
{
  NSWindow* pWindow = [self window];
  
  if (pWindow)
  {
   ...   
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(windowDidResign:)
                                                 name:NSWindowDidResignKeyNotification
                                               object:pWindow];
    
    [[NSNotificationCenter defaultCenter] addObserver:self
                                             selector:@selector(windowDidResign:)
                                                 name:NSWindowDidResignMainNotification
                                               object:pWindow];
}

- (void) windowDidResign: (NSNotification*)notification
{
  mGraphics->OnLostFocus();
}

- (BOOL) resignFirstResponder
{
  mGraphics->OnLostFocus();
  return YES;
}
  1. A new method has also been added to the IGraphics and IControl classes: void OnLostFocus(), which reacts to the loss of focus by the plugin window. In my case, pop-up lists and pop-up menus are hidden.
    In principle, everything works as desired - when switching focus, the list closes, however, if any pop-up menu appears on the screen, such as in the screenshot below, then none of my methods work. I would like to track the appearance of any other pop-up menus on the screen and get a loss of focus event, but alas, I am not such a big expert on macOS, so I ask for help from knowledgeable colleagues.

1 Like

I also want to inform you that this topic is relevant for all those who use IPopupMenuControl, since this menu does not disappear from the screen when changing focus, and this, in turn, is not good (the standard pop-up menu always disappears from the screen when deactivated).

1 Like

Thanks for this. We should add it. For future reference, it’s best to make an issue on github and a PR, rather than post code here.

here is a work in progress

Thanks Oli. However, there are some nuances that have not been fully tested on different operating systems and DAWs. In particular, I recorded a drop in DAW at closing. As I found out, the reason for the crash is sending a notification NSWindowDidResignKeyNotification at the time of destroy of controls. I decided to make a check for the presence of a timer in the IGraphicsMac_view.mm file:

- (void) windowDidResign: (NSNotification*)notification
{
  if (mTimer == nil)
    return;
  mGraphics->OnLostFocus();
}

In this case, the OnLostFocus() event is not sent.

You also need to add the method to IControl:

/** This is an called when focus is lost. /todo check this */
  virtual void OnLostFocus() {}

And in class IGraphics -
to IGraphics.h:
void OnLostFocus();
to IGraphics.cpp:

void IGraphics::OnLostFocus()
{
  TRACE
  ForAllControls(&IControl::OnLostFocus);
}

In IGraphicsWin.cpp add WM_KILLFOCUS message processing like this:

case WM_KILLFOCUS:
    {
      pGraphics->OnLostFocus();
      return 0;
    }

This makes me happy. The main thing is that IControl includes a new virtual method OnLostFocus(), which can be overridden in user control, for example, as I did in my DReverb2 plugin menu, so that if focus is lost, menu can disappear from the screen.

image

Hi Oli,

is there a reason why

if (mTimer == nil)
    return;

was not considered in the PR above?
Or is this covered elsewhere?

At least I need this hack to avoid a repeated crash with MAC M1…
Thank you!

I suggested this code to Ole. Simply by the presence of a timer, you can determine the validity of the object and leave the function at the end of work in order to avoid errors.
Unfortunately, I haven’t tested this code on MAC M1, but it works fine on MAC x86-64.

We tested on Sequoia M1. The addition fixes menu related crashes.
Thank you for this!!