Search code examples
cocoanpapi

Firefox Cocoa Plugin


I`ve created simple hello world-like plugin which draws red box.

Аfter embedding into xulrunner application the plugin works almost fine. Xulrunner application successfully redraws the box on resizing the application window.

But after any mouse event, for instance - left click, my application crashes with "Stack overflow". Debugger says the reason is endless cycle of 2 calls of forwardMethod followed by one call of JSD_GetValueForObject

After the crash stack contents is the next:

  • -[NSApplication _indexOfWindow:]
  • -[NSEvent window]
  • JSD_GetValueForObject
  • JSD_GetValueForObject
  • JSD_GetValueForObject
  • forwardMethod
  • forwardMethod
  • JSD_GetValueForObject
  • forwardMethod
  • forwardMethod
  • JSD_GetValueForObject
  • forwardMethod
  • forwardMethod
  • JSD_GetValueForObject
  • forwardMethod
  • forwardMethod
  • JSD_GetValueForObject
  • forwardMethod
  • forwardMethod
  • JSD_GetValueForObject
  • forwardMethod
  • forwardMethod
  • .....etc

My code is:

int16_t NPP_HandleEvent(NPP instance, void* event)
{
    EventRecord* carbonEvent = (EventRecord*)event;

    if (carbonEvent && (carbonEvent->what == updateEvt))
    {       
        PluginInstance* currentInstance = (PluginInstance*)(instance->pdata);
        CGContextRef cgContext = ((NP_CGContext*)(currentInstance->window.window))->context;
        float windowWidth = currentInstance->window.width;
        float windowHeight = currentInstance->window.height;

        static int x = 0;

        if (x++)
            return;

        NPRect clipRect = currentInstance->window.clipRect;

        NP_CGContext* npContext = currentInstance->window.window;

        NSWindow* browserWindow = [[[NSWindow alloc] initWithWindowRef:npContext->window] autorelease];

        int y = [browserWindow frame].size.height - (clipRect.bottom - clipRect.top) -  currentInstance->window.y;

        //[plugin attachToWindow:browserWindow at:NSMakePoint(window->x, y)];
        NSPoint point = NSMakePoint(currentInstance->window.x, y);

        // find the NSView at the point
        NSView* hitView = [[browserWindow contentView] hitTest:NSMakePoint(point.x+1, point.y+1)];
        if (hitView == nil || ![[hitView className] isEqualToString:@"ChildView"]) 
        {
            x = 0;
            return;
        }

        NSView* parentView = hitView;       

        NSBox *box = [[NSBox alloc] initWithFrame:NSMakeRect(0.0, 0.0, 100, 100)];
        [box setBoxType:NSBoxCustom];
        [box setBorderType:NSLineBorder];
        [box setTitlePosition:NSNoTitle];
        [box setFillColor:[NSColor redColor]];

        [parentView addSubview:box];

        //DrawPlugin(cgContext, windowWidth, windowHeight);
    }

    return 0;
}

Solution

  • I do not think that Cocoa and the old EventRecord system mix together very well.

    A cocoa event model is now avalaible in the last build of mozilla.

    Check-out the tree for comm-central with Mercurial and try it:
    hg clone http://hg.mozilla.org/mozilla-central/ src
    The path to the Xcode project is:
    src/modules/plugin/sdk/samples/basic/mac/
    and the plugin must be copied to:
    /Library/Internet Plug-Ins/

    I tried it myself with the basic firefox plugin and the cocoa event system works.
    I just do not know how to get a pointer to the current NSView.

    I think it had to be done for the 64 bits version of Firefox on mac. It is not available in Firefox 3.6, but might be in Firefox 3.7, and the version of the NPAPI SDK with the Cocoa event model is the version 0.23.

    EDIT:
    To try it directly without mercurial download the latest mozilla build as Misha at:
    http://ftp.mozilla.org/pub/mozilla.org/xulrunner/nightly/latest-trunk/
    The Xcode project with the Cocoa event model is at:
    http://mxr.mozilla.org/mozilla-central/source/modules/plugin/sdk/samples/basic/mac/

    The NetscapeCocoaPlugin sample in the Webkit sources use the cocoa event model too.