FLTK windows in Mac OS X共享同一个系统菜单

FLTK windows in Mac OS X share the same system menu

当OS X 中的某些应用程序有多个windows(许多打开的文档,每个都在自己的window)时,似乎它们都共享相同的系统菜单,至少在 FLTK 中。有没有办法从菜单中找到最近 selected window 向其发送事件?

这是我的设置(Mac OS X 10.6.2,FLTK 1.3.3):有 Shell class 和系统菜单。每次打开新文档时,都会创建新的 Shell

#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

然后我跟踪最近 selected Shell 保存到 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;
    ...
}

这件作品似乎有效,因为我每次 select 一些 Shell:

时都能看到痕迹
Select shell with address: [0x8206db0]
Select shell with address: [0x82375f0]
Select shell with address: [0x5d20650]
Select shell with address: [0x82375f0]

现在,给出:

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;
}

我有一些回调:

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

当从菜单执行此回调并打开更多 Shell 时,出现以下错误:

Bus error

没有来自 Shell::shortcutCBShell::currentShell 的踪迹。当唯一的 Shell 打开时,一切正常。当更多 Shell 打开并且我关闭除一个以外的所有时,错误再次出现。从 Shell 内的某个小部件调用或从键盘快捷键传递相同的回调时没有问题。

通过以下 3 个步骤解决了问题:

  1. 在 OS X 中声明菜单栏也是静态的(这里失败了):

    #ifdef __APPLE__
        static Fl_Sys_Menu_Bar *s_menubar;
    #else
        Fl_Sys_Menu_Bar *m_menubar;
    #endif
    
  2. 不仅在 FL_FOCUS 事件上保存当前 Shell::s_current,而且在 Shell 处理的任何事件上,即每次 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. 在 OS X 上使用 Shell::s_current 进行菜单回调,无论是否生成调用的小部件:

    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;
    }