views:

879

answers:

4

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;
}
+1  A: 

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.

Winz
Actually Cocoa event model is not supported under 32 bit.That is why all of the 32 bit cocoa plugins have to use Carbon event model and can`t use such great things like CoreAnimation which require Cocoa event model.
Mischa
Mischa: Do you mean in Netscape plug-ins? It's supported under 32-bit just fine in applications.
Peter Hosey
It is not a carbon event model, which uses EventRef. EventRecord is a legacy model from "Classic" Mac OS.
Winz
>Mischa: Do you mean in Netscape plug-ins? Of cource, yes, in Netscape plugins. It is only the problem of the Netscape Cocoa 32bit plugins.
Mischa
Thank you, Winz!Could you please tell me exactly which version of Mozilla you used?And it would be great if you give a sample hello-world like Xcode project for download - or simply e-mail it to me ( [email protected] ). I`ve got a feeling that i`m doing something wrong with the Xcode settings or something.
Mischa
... because i`ve already tried the latest versions of Xulrunner, including the latest beta version and NPNVsupportsCocoaBool test always returned false.
Mischa
Gecko 1.9.3 is the first version to support the Cocoa event model.
smorgan
+2  A: 

Thank you, Winz, very much!

I`ve just downloaded the latest mozilla build and SDK from

http://ftp.mozilla.org/pub/mozilla.org/xulrunner/nightly/latest-trunk/

And BasicPlugin.xcodeproj from

http://mxr.mozilla.org/mozilla-central/source/modules/plugin/sdk/samples/basic/mac/

Cocoa event model is now accessible.

Mischa
Yes I used the latest build and not the lastest beta. I was trying to get a pointer on a NSView before sending you a email, but I have not succeded yet. Moreover in the source code of firefox there is an other class called nsview too! Do not hesitate to edit or post an answer to tell us how you embedded your application ^_^
Winz
A: 

I just do not know how to get a pointer to the current NSView

Hello, Winz!

The answer seems to be obvious- we can obtain NSView using EventRecord legacy event model and AFTER THAT switch to Cocoa event model by adding the line:

browser->setvalue(instance, NPPVpluginEventModel, (void*)NPEventModelCocoa);

My application become absolutely stable after that. No more crashes!!!

I`ve just received an NPCocoaEventDrawRect after activating the main window of my application. So the cocoa event model seems to work.

Mischa
I will test that, thank you. I tried with the sample "NetscapeCocoaPlugin" from the lastest Webkit sources: a call to [NSView focusView] in NPP_SetWindow returns the current NSView too.
Winz
You should absolutely not do this. Per https://wiki.mozilla.org/NPAPI:Models "Changing models outside of NPP_New is not allowed." The fact that it is working for you is an accident of implementation. You cannot get a pointer to the native NSView under the Cocoa event model, and that's by design. Any workaround you manage to come up with is going to fail as soon your plugin is run out of process.
smorgan
A: 

Hi

I am not sure if this is related but i am running into the same problem (firefox crashes when the mouse hovers over the viewing area). I am using the latest firefox and this is what I did so far:

  1. In NPP_New() I did the following to set the event model to cocoa

    NPBool supportsCG = false;
    NPError err = browser.getvalue(m_Instance, NPNVsupportsCoreGraphicsBool, &supportsCG);
    
    
    if (err) {
        log << logHeader << funcName << " supportsCG = " << supportsCG << endl;
    }
    
    
    err = browser.setvalue(m_Instance, NPPVpluginDrawingModel, (void*) NPDrawingModelCoreGraphics);
    
    
    if (err) {
        log << logHeader << funcName << " failed to set CG drawing model = " << err << endl;
    }
    
    
    err = browser.setvalue(m_Instance, NPPVpluginEventModel, (void*) NPEventModelCocoa);
    if (err) {
        log << logHeader << funcName << " failed to set cocal event model = " << err << endl;
    }
    
  2. In NPP_SetWindow(), I did the following:

    NP_CGContext* npContext = (NP_CGContext*) browserNPWindow->window;
    NSWindow* browserWindow = [[[NSWindow alloc] initWithWindowRef:npContext->window]autorelease];
    
    
    // convert to CG co-ordinates
    int y = [browserWindow frame].size.height - browserNPWindow->height - browserNPWindow->y;
    NSView* browserView = [[browserWindow contentView] hitTest:NSMakePoint(browserNPWindow->x+1, y+1)];
    NSView* myView = [[NSView alloc]init];
    
    
    [myView setFrame:[browserView bounds]];
    [browserView addSubview:myView];
    NSRect frame = [myView bounds];
    
    
    // drawing code uses the frame to draw
    
  3. I suspect there could be a problem in NPP_SetWindow() code, but couldn't figure out where the problem exists. Any help is appreciated. Thanks.

Marlin Tester
Your problem is that npContext->window is not a WindowRef under the Cocoa event model; in fact, it is always NULL. See <https://wiki.mozilla.org/NPAPI:CocoaEventModel>. What you are trying to do (get a pointer to the native view) is not possible under the Cocoa event model.
smorgan