如何在 Firebreath NPAPI 插件中将 NSMenu 连接到 NSStatusItem,以便在单击状态栏项时出现菜单?

Posted

技术标签:

【中文标题】如何在 Firebreath NPAPI 插件中将 NSMenu 连接到 NSStatusItem,以便在单击状态栏项时出现菜单?【英文标题】:How to connect NSMenu to NSStatusItem in a Firebreath NPAPI plugin so the menu appears when clicking the StatusBar Item? 【发布时间】:2012-09-18 23:32:00 【问题描述】:

作为 NPAPI Chrome 浏览器插件的一部分,我正在努力在 Mac OS 状态栏中显示一个带有菜单的状态图标。

Firebreath 使用 C++,而大多数用于 Mac OS 开发的库都使用 Objective C。感谢this question 上的回复,我克服了这个障碍。我还必须调整我的 CMake 设置才能将 XIB 文件编译为 NIB。

经过反复试验,我能够让状态栏选项出现在状态栏中,但是当我单击它时,菜单不会展开。我不确定我需要做什么才能显示菜单。它适用于 Cocoa 应用程序,但不适用于 Firebreath 应用程序。

我也导入了 Foundation 和 Cocoa 库。

我怀疑问题出在我的 MainMenu.xib 文件或 AppDelegate.m 中。

AppDelegate.m:

#import "AppDelegate.h"   

@implementation AppDelegate

-(void)awakeFromNib 
    NSLog(@"calling awakeFromNib...");

    NSStatusBar *bar = [NSStatusBar systemStatusBar];
    statusItem = [[bar statusItemWithLength:NSVariableStatusItemLength ] retain];


   // statusItem = [[NSStatusBar systemStatusBar] statusItemWithLength:NSVariableStatusItemLength];
    //[statusItem retain];
    NSMenuItem *menuItem;


    menuItem = [[[NSMenuItem alloc] initWithTitle:@"Test" action:NULL keyEquivalent:@""] retain];
//    [menuItem setView: myView];
    statusMenu = [statusMenu initWithTitle:@"WTF"];
    [statusMenu addItem:menuItem];

    [menuItem retain];
    [statusItem setTitle: NSLocalizedString(@"StatusMenu",@"")];
    [statusItem setHighlightMode:YES];
    [statusItem setMenu:statusMenu];
    [statusItem setEnabled:YES];

    [statusMenu retain];

    // this was needed to get the icon to display
    [statusItem retain];
    //[window retain];


- (IBAction)settings:(id)sender 
    NSLog(@"Invoking the settings from the menu...");



//@synthesize window;
@end

此文件是从示例应用程序中获取的,并且正在从 Objective C++ 包装类手动调用 awakeFromNib。根据日志,以及我在状态栏中看到“StatusMenu”这一事实,我知道正在调用此函数。

我还附上了 MainMenu.xib 的屏幕截图:

MainMenu.xib:

我尝试的最后一件事是将 NSStatusItem 添加为 IBOutlet 以查看是否可以将其连接到 xib 文件中的某些内容,但我不确定这是正确的方向。

单击“状态菜单”选项时需要做什么才能显示菜单?

【问题讨论】:

当您说“awakeFromNib 正在从 Objective C++ 手动调用”时,您涉及的是NSBundle 还是NSNib?如果没有,我怀疑你需要这样做。也许The Nib Object Life Cycle 或Loading Nib Files Programmatically 会有所帮助。 嗨@JoshCaswell,在示例应用程序中,我认为它被处理加载应用程序的其他进程调用,但 Firebreath 框架使用 C++ 和其他一些机制来启动应用程序。我正在从 Objective C++ 包装器中调用 awakeFromNib。我会看看 NSBundle 和 NSLib 以及那个链接。谢谢你的提示;当我了解更多信息时,我会更新我的问题。 请记住,可能没有 NSApplication 并且您可能无法创建一个;这些是生活在别人的过程中的缺点。 @taxilian - Google 有一个Google Talk Chrome Extension,它使用 NPAPI 在 Windows 和 Mac OS 中安装状态栏图标。右键单击显示选项,左键单击加载 Chrome 面板。我已经有了状态栏图标,所以我的想法是尝试注册一个我可以绑定的点击事件。我想我不需要与操作系统完全集成,事实上,抛出一个扩展可以绑定的事件会更跨平台兼容。所以如果 NSApplication 不可用,我会试试这个。 好的,事实证明我没有在 NSMenu 对象上调用 alloc,并且 Objective C 不会像 Java 那样抛出 NPE 或像 javascript 在这种情况下会发生的未定义错误。添加 alloc 后,我可以以编程方式将项目添加到菜单并在单击时触发日志事件。简而言之,我完全绕过了 xib/nib,如果这意味着进入下一个挑战,这对我来说没问题。 【参考方案1】:

这里的问题是 Firebreath 项目和 NPAPI 插件架构不支持自动引用计数 (ARC),通常在 XCode 项目中默认开启。

此外,由于将 Objective C 与 C++ 混合的疯狂,XCode 并不能像纯粹用 Objective C 编写代码那样容易地报告错误。因此,错误消息被抑制了。为了避免错误,使用 NPAPI 插件架构的开发人员必须通过在 NSMenu 对象上调用 alloc 来显式管理内存。

只要对这些对象调用 alloc,它们就会被正确保留。这解决了问题。

【讨论】:

以上是关于如何在 Firebreath NPAPI 插件中将 NSMenu 连接到 NSStatusItem,以便在单击状态栏项时出现菜单?的主要内容,如果未能解决你的问题,请参考以下文章

结合FireBreath在Chrome/FireFox的多进程模式下崩溃一例

仅使用 Firefox Addon SDK 在后台嵌入 NPAPI 插件

NPAPI 迁移到 NaCl 的 Google chrome 扩展

Unix 域套接字和 NPAPI

你如何为 IE 开发插件?

Firebreath 中的 IPC (boost c++)