2012-11-08 48 views
1

我有一些問題,我用xcode在mac10.8上寫了一個npapi插件,我想在插件上繪製一張圖片,但是當我通過NPP_SetWindow獲得pNPWindow->窗口指針時(NPP實例,NPWindow * pNPWindow);我發現,nNPWindow->窗口爲NULL,我花一定要找到這個問題,但我不能,有人能幫助我。對不起,我的英語這麼差。在mac10.8上開發的NPAPI插件

代碼就是這樣,

NPError NPP_New(NPMIMEType pluginType, NPP instance, uint16_t mode, int16_t argc, char*  argn[], char* argv[], NPSavedData* saved) 
    { 
     if(instance == NULL) 
      return NPERR_INVALID_INSTANCE_ERROR; 

     CPlugin *plugin = new CPlugin(instance); 
     if(plugin == NULL) 
      return NPERR_OUT_OF_MEMORY_ERROR; 
     instance->pdata = (void *)plugin; 

     NPBool supportsCG = false; 
     NPError err; 
     err = browser->getvalue(instance, NPNVsupportsCoreGraphicsBool,&supportsCG); 

     if (err == NPERR_NO_ERROR && supportsCG) 
      browser->setvalue(instance,NPPVpluginDrawingModel,(void*)NPDrawingModelCoreGraphics); 

     return NPERR_NO_ERROR; 
    } 

    NPError NPP_SetWindow(NPP instance, NPWindow* pNPWindow) 
    { 
     if(instance == NULL) 
      return NPERR_INVALID_INSTANCE_ERROR; 
     if(pNPWindow == NULL) 
      return NPERR_GENERIC_ERROR; 

     if(pNPWindow->window) 
      writelog("window != NULL"); 

     if(pNPWindow->window == NULL) //this is he problem pNPWindow->window always NULL 
      writelog("window == NULL"); 

     return NPERR_NO_ERROR; 
    } 

回答

2

任何你要在Mac 10.8上使用的東西都不支持碳事件模型,所以窗口將始終爲NULL。假設您正在嘗試使用CoreGraphics繪圖模型,您將在觸發繪製事件時獲取CGContextRef。

有關Cocoa事件模型的更多信息,請參閱https://wiki.mozilla.org/NPAPI:CocoaEventModel。你有另一種選擇是CoreAnimation模型(與InvalidatingCoreAnimation模型上的Firefox和Chrome)

你可能想看看FireBreath,這適用於10.8和抽象所有的這些東西併發症的爲您服務。

+1

作爲後續工作,如果您希望插件在現代瀏覽器中作爲32位插件工作,則應該與CoreGraphics繪圖模型一起協商Cocoa事件模型。我猜你正在測試64位,因爲你看到Cocoa事件模型的行爲(NULL窗口指針),但沒有在你發佈的代碼中使用Cocoa協商。 Cocoa是64位的默認值,但不是32位,如果你希望你的插件在Chrome中(或者在32位模式下啓動瀏覽器的人)工作,你應該爲這兩者編譯。 – smorgan

+0

非常好的一點 – taxilian

0

NPP_SetWindow(NPP npp,NPWindow * pNPWindow)

對於很多人來說,這將是真正的樂趣開始的地方 - 調用這個函數來告訴插件他們在哪個窗口。從Gecko SDK(npapi.h):

typedef struct _NPWindow 
{ 
    void* window; /* Platform specific window handle */ 
      /* OS/2: x - Position of bottom left corner */ 
      /* OS/2: y - relative to visible netscape window */ 
    int32 x;  /* Position of top left corner relative */ 
    int32 y;  /* to a netscape page.     */ 
    uint32 width; /* Maximum window size */ 
    uint32 height; 
    NPRect clipRect; /* Clipping rectangle in port coordinates */ 
       /* Used by MAC only.   */ 
    void * ws_info; /* Platform-dependent additonal data, linux specific */ 
    NPWindowType type; /* Is this a window or a drawable? */ 
} NPWindow; 

每次調用都會傳入一個指向此結構的指針。在Windows上,「void * window」將取消引用HWND。在其他平臺上,它也將作爲適當的類型取消引用。

請注意,再次NPP npp是第一個參數。在除NPP_New之外的所有NPP函數中都會出現這種情況,因爲我們創建了一個PluginInstance對象並將其分配給NPP_New中的npp-> pdata,所以我們需要創建一個小的存根函數來將NPP_New轉發給該對象的一個​​方法,像這樣:

//通過瀏覽器只要窗口被改變,包括建立或銷燬

NPErrorNPP_SetWindow (NPP npp, NPWindow* pNPWindow) 
{ 
    if (npp == NULL) 
     return NPERR_INVALID_INSTANCE_ERROR; 
    else if (npp->pdata == NULL) 
     return NPERR_GENERIC_ERROR; 

    PluginInstance *inst = (PluginInstance *)npp->pdata; 
    return inst->NpapiSetWindow(pNPWindow); 
} 

在Windows上,時調用SetWindow叫我們需要保存HWND併爲窗口創建子類,以便我們可以獲得我們自己的窗口事件過程。

NPError PluginInstance :: NpapiSetWindow(NPWindow * pNPWindow) { NPError rv = NPERR_NO_ERROR;

if(pNPWindow == NULL) 
    return NPERR_GENERIC_ERROR; 

// window just created; in initWindow, set initialized to true 
if(!this->initialized) { 
    if(!this->initWindow(pNPWindow)) { 
     return NPERR_MODULE_LOAD_FAILED_ERROR; 
    } 
} 

// Window was already created; just pass on the updates 
this->updateWindow(pNPWindow); 

return rv; 
} 

有了這些功能,我們在一個函數得到通知時窗口是第一套,而另一個被稱爲更新由各一次。