Search code examples
macosuser-interfacefltk

FLTK windows in Mac OS X share the same system menu


When some application in OS X has multiple windows (many open documents, each in own window), it seems that all them share the same system menu, at least in FLTK. Is there a way to find the most recent selected window to send an event to it from the menu?

Here is my setup (Mac OS X 10.6.2, FLTK 1.3.3): have Shell class with system menu. Each time new document is opened, new Shell is created:

#ifdef __APPLE__
void Shell::macOpen(const char *fileName)
{
    // If there are empty shell, open the model in it
    if (s_empty != 0)
    {
        ...
        s_empty = 0;
    }
    // Otherwise, create new shell with the model
    else
    {
        char *args[1];
        args[0] = (char *) fileName;
        new Shell(1, args, s_conf, s_dct, fileName, 1);
    }
}
#endif

Then I keep track on the most recently selected Shell saving it into static Shell *Shell::s_current:

int Shell::handle(int event)
{
    ...
    case FL_FOCUS:
#ifdef __APPLE__
        // We just selected some shell, it is current.
        s_current = this;
        cout << "Select shell with address: [" << s_current << "]" << endl;
#endif
        return 1;
    ...
}

This piece seems to work, as I can see the traces each time I select some Shell:

Select shell with address: [0x8206db0]
Select shell with address: [0x82375f0]
Select shell with address: [0x5d20650]
Select shell with address: [0x82375f0]

Now, given:

Shell *Shell::currentShell(Fl_Widget *w)
{
    cout << "Widget address: [" << w << "]" << endl;
    Shell *result = 0;
    if (w != 0)
    {
        result = (Shell *) w->window();
        cout << "Widget wingow address: [" << result << "]" << endl;
    }
#ifdef __APPLE__
    else
    {
        result = s_current;
        cout << "Last selected shell address: [" << result << "]" << endl;
    }
#endif
    return result;
}

I have some callback:

void Shell::shortcutCB(Fl_Widget *w, void *data)
{
    cout << "Shortcut" << endl;
    Shell *ref = currentShell(w);
    if (ref != 0)
    {
         ...
    }
}

When this callback is executed from the menu and more Shells are open, I get the following error:

Bus error

With no trace from either Shell::shortcutCB or Shell::currentShell. When the only Shell is open, all works perfectly. When more Shells are open and I close all but one, the error arises again. There is no problems when the same callback is called from some widget within Shell or is delivered from keyboard shortcut.


Solution

  • Solved the problem with the following 3 steps:

    1. Declaring manu bar in OS X also static (here was the fail):

      #ifdef __APPLE__
          static Fl_Sys_Menu_Bar *s_menubar;
      #else
          Fl_Sys_Menu_Bar *m_menubar;
      #endif
      
    2. Save current Shell::s_current not only on FL_FOCUS event, but on any event handled by Shell, that is, each time it returns 1:

      int Shell::handle(int event)
      {
          int result = 0;
          switch (event)
          {
              // Set result = 1 when handling the event
              ...
          }
      #ifdef __APPLE__
          if (result == 1)
          {
              // We just selected some shell, it is current.
              s_current = this;
              cout << "Select shell with address: [" << s_current << "]" << endl;
          }
      #endif
          return result;
      }
      
    3. Use Shell::s_current for menu callbacks on OS X regardless of generating widget of the call:

      Shell *Shell::currentShell(Fl_Widget *w)
      {
          Shell *result = 0;
      #ifdef __APPLE__
          result = s_current;
          cout << "Last selected shell address: [" << result << "]" << endl;
      #else
          cout << "Widget address: [" << w << "]" << endl;
          if (w != 0)
          {
              result = (Shell *) w->window();
              cout << "Widget wingow address: [" << result << "]" << endl;
          }
      #endif
          return result;
      }