mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-11-08 04:27:37 +00:00
2191 lines
60 KiB
C++
2191 lines
60 KiB
C++
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||
*
|
||
* The contents of this file are subject to the Netscape Public License
|
||
* Version 1.0 (the "NPL"); you may not use this file except in
|
||
* compliance with the NPL. You may obtain a copy of the NPL at
|
||
* http://www.mozilla.org/NPL/
|
||
*
|
||
* Software distributed under the NPL is distributed on an "AS IS" basis,
|
||
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the NPL
|
||
* for the specific language governing rights and limitations under the
|
||
* NPL.
|
||
*
|
||
* The Initial Developer of this code under the NPL is Netscape
|
||
* Communications Corporation. Portions created by Netscape are
|
||
* Copyright (C) 1998 Netscape Communications Corporation. All Rights
|
||
* Reserved.
|
||
*/
|
||
|
||
// All the code-resource handling stuff has been adopted from:
|
||
// Multi-Seg CR example in CW
|
||
// Classes:
|
||
// CPluginInstance - one per plugin instance. Needs to call the functions
|
||
// CPluginHandler - one per plugin MIME type
|
||
|
||
#include "CHTMLView.h"
|
||
|
||
#include "macutil.h"
|
||
#include "npapi.h"
|
||
#include "mplugin.h"
|
||
#include "uprefd.h"
|
||
#include "ufilemgr.h"
|
||
#include "uapp.h" // might be unnecessary when we get rid of CFrontApp
|
||
#include "resgui.h"
|
||
#include "miconutils.h"
|
||
#include "uerrmgr.h"
|
||
#include "macgui.h"
|
||
#include "resae.h"
|
||
#include "edt.h" // for EDT_RegisterPlugin()
|
||
#include "CApplicationEventAttachment.h"
|
||
|
||
#if defined(JAVA)
|
||
#include "java.h" // for LJ_AddToClassPath
|
||
#endif
|
||
|
||
#include "np.h"
|
||
#include "nppg.h"
|
||
#include "prlink.h"
|
||
|
||
#include "npglue.h"
|
||
#include "nsIEventHandler.h"
|
||
|
||
#ifdef LAYERS
|
||
#include "layers.h"
|
||
#include "mkutils.h"
|
||
#endif // LAYERS
|
||
|
||
#include "MixedMode.h"
|
||
#include "MoreMixedMode.h"
|
||
#include <CodeFragments.h>
|
||
|
||
#include "LMenuSharing.h"
|
||
#include "CBrowserWindow.h"
|
||
|
||
// On a powerPC, plugins depend on being able to find qd in our symbol table
|
||
#ifdef powerc
|
||
// #pragma export qd
|
||
// beard: this seems to be an illegal pragma
|
||
#endif
|
||
|
||
const ResIDT nsPluginSig = 128; // STR#, MIME type is #1
|
||
|
||
struct _np_handle;
|
||
|
||
|
||
// *************************************************************************************
|
||
//
|
||
// class CPluginHandler
|
||
//
|
||
// *************************************************************************************
|
||
|
||
class CPluginHandler
|
||
{
|
||
friend void FE_UnloadPlugin(void* plugin, struct _np_handle* handle);
|
||
friend NPPluginFuncs* FE_LoadPlugin(void* plugin, NPNetscapeFuncs *, struct _np_handle* handle);
|
||
|
||
public:
|
||
|
||
// <20><> constructors
|
||
CPluginHandler(FSSpec& plugFile);
|
||
~CPluginHandler();
|
||
|
||
// <20><> xp->macfe
|
||
static Boolean CheckExistingHandlers(FSSpec& file);
|
||
NPPluginFuncs* LoadPlugin(NPNetscapeFuncs * funcs, _np_handle* handle);
|
||
void UnloadPlugin();
|
||
|
||
// plugin -> netscape
|
||
static void Status(const char * message);
|
||
|
||
static CPluginHandler* FindHandlerForPlugin(const CStr255& pluginName);
|
||
|
||
private:
|
||
|
||
// <20><> funcs
|
||
OSErr InitCodeResource(NPNetscapeFuncs * funcs, _np_handle* handle);
|
||
void CloseCodeResource(_np_handle* handle = NULL);
|
||
void ResetPlugFuncTable();
|
||
void OpenPluginResourceFork(Int16 inPrivileges);
|
||
|
||
// <20><> vars
|
||
short fRefCount;
|
||
PRLibrary* fLibrary; // For PPC
|
||
Handle fCode; // For 68K
|
||
NPPluginFuncs fPluginFuncs; // xp->plugin
|
||
NPP_MainEntryUPP fMainEntryFunc;
|
||
NPP_ShutdownUPP fUnloadFunc;
|
||
LFile* fFile; // File containing the plugin
|
||
CStr255 fPluginName; // Name of plug-in
|
||
|
||
CPluginHandler* fNextHandler; // Link to next handler in the global list
|
||
static CPluginHandler* sHandlerList; // Global list of all handlers
|
||
};
|
||
|
||
CPluginHandler* CPluginHandler::sHandlerList = NULL;
|
||
|
||
void* GetPluginDesc(const CStr255& pluginName)
|
||
{
|
||
return CPluginHandler::FindHandlerForPlugin(pluginName);
|
||
}
|
||
|
||
//
|
||
// Find a handler given a plug-in name (currently only
|
||
// called from CFrontApp:RegisterMimeType).
|
||
//
|
||
CPluginHandler* CPluginHandler::FindHandlerForPlugin(const CStr255& pluginName)
|
||
{
|
||
CPluginHandler* handler = CPluginHandler::sHandlerList;
|
||
while (handler != NULL)
|
||
{
|
||
if (handler->fPluginName == pluginName)
|
||
return handler;
|
||
|
||
handler = handler->fNextHandler;
|
||
}
|
||
|
||
return nil;
|
||
}
|
||
|
||
|
||
//
|
||
// Check the handlers we already have registered against
|
||
// the given file spec. We don<6F>t want to redundantly
|
||
// create handlers for the same plugin file.
|
||
//
|
||
Boolean CPluginHandler::CheckExistingHandlers(FSSpec& file)
|
||
{
|
||
CPluginHandler* handler = CPluginHandler::sHandlerList;
|
||
while (handler != NULL)
|
||
{
|
||
if (handler->fFile)
|
||
{
|
||
FSSpec existingFile;
|
||
handler->fFile->GetSpecifier(existingFile);
|
||
if (existingFile.vRefNum == file.vRefNum && existingFile.parID == file.parID)
|
||
{
|
||
if (EqualString(existingFile.name, file.name, true, true))
|
||
return false;
|
||
}
|
||
}
|
||
handler = handler->fNextHandler;
|
||
}
|
||
return true;
|
||
}
|
||
|
||
|
||
// <20><> constructors
|
||
|
||
CPluginHandler::CPluginHandler(FSSpec& plugFile)
|
||
{
|
||
// Variables
|
||
fRefCount = 0;
|
||
fCode = NULL;
|
||
fLibrary = NULL;
|
||
fFile = NULL;
|
||
fMainEntryFunc = NULL;
|
||
fUnloadFunc = NULL;
|
||
fNextHandler = NULL;
|
||
fPluginName = "";
|
||
|
||
Try_
|
||
{
|
||
fFile = new LFile(plugFile);
|
||
fFile->OpenResourceFork(fsRdPerm);
|
||
|
||
// Look for the plug-in description resource
|
||
CStringListRsrc descRsrc(126);
|
||
CStr255 pluginDescription;
|
||
|
||
// Read plug-in description if available; if not, use blank description
|
||
short descCount = descRsrc.CountStrings();
|
||
if (descCount > 0)
|
||
descRsrc.GetString(1, pluginDescription);
|
||
if (descCount <= 0 || ResError())
|
||
pluginDescription = "";
|
||
|
||
// Read plug-in name if available; if not, use file name
|
||
if (descCount > 1)
|
||
descRsrc.GetString(2, fPluginName);
|
||
if (descCount <= 1 || ResError())
|
||
fPluginName = plugFile.name;
|
||
|
||
// cstring fileName((const unsigned char*) plugFile.name);
|
||
char* fileName = CFileMgr::EncodedPathNameFromFSSpec(plugFile, TRUE);
|
||
ThrowIfNil_(fileName);
|
||
fileName = NET_UnEscape(fileName);
|
||
NPError err = NPL_RegisterPluginFile(fPluginName, fileName, pluginDescription, this);
|
||
XP_FREE(fileName);
|
||
ThrowIfOSErr_(err);
|
||
|
||
CStringListRsrc mimeList(128);
|
||
CStringListRsrc descList(127);
|
||
|
||
UInt32 mimeTotal = mimeList.CountStrings() >> 1; // 2 strings per entry
|
||
UInt32 descTotal = descList.CountStrings();
|
||
UInt32 count, mimeIndex, descIndex;
|
||
ThrowIf_(mimeTotal == 0);
|
||
|
||
for (count = mimeIndex = descIndex = 1; count <= mimeTotal; count++, mimeIndex += 2, descIndex++)
|
||
{
|
||
CStr255 mimeType;
|
||
CStr255 extensions;
|
||
CStr255 description;
|
||
|
||
mimeList.GetString(mimeIndex, mimeType);
|
||
if (ResError())
|
||
continue;
|
||
|
||
mimeList.GetString(mimeIndex + 1, extensions);
|
||
if (ResError())
|
||
continue;
|
||
|
||
//
|
||
// Get the description string from the plug-in.
|
||
// If they didn't specify one, use a pre-existing
|
||
// description if it exists (e.g. we know by default
|
||
// that video/quicktime is "Quicktime Video"). If
|
||
// we still didn't find a description, just use the
|
||
// MIME type.
|
||
//
|
||
Boolean gotDescription = false;
|
||
if (descIndex <= descTotal)
|
||
{
|
||
descList.GetString(descIndex, description);
|
||
gotDescription = (ResError() == noErr);
|
||
}
|
||
if (!gotDescription)
|
||
{
|
||
NET_cdataStruct temp;
|
||
NET_cdataStruct* cdata;
|
||
char* mimetype = (char*) mimeType;
|
||
|
||
memset(&temp, 0, sizeof(temp));
|
||
temp.ci.type = mimetype;
|
||
cdata = NET_cdataExist(&temp);
|
||
if (cdata && cdata->ci.desc)
|
||
description = cdata->ci.desc;
|
||
else
|
||
description = mimeType;
|
||
}
|
||
|
||
//
|
||
// Look up this type in the MIME table. If it's not found, then
|
||
// the user hasn't seen this plug-in type before, so make a new
|
||
// mapper for the table with the type defaulted to be handled by
|
||
// the plug-in. If it was found, but was from an old prefs file
|
||
// (that didn't contain plug-in information), make sure the plug-
|
||
// in still gets priority so users don't freak out the first time
|
||
// they run a new Navigator and the plug-ins stop working. If it
|
||
// was found but was latent (disabled because the plug-in was
|
||
// missing), re-enable it now because the plug-in is present again.
|
||
//
|
||
cstring type((const unsigned char*) mimeType);
|
||
CMimeMapper* mapper = CPrefs::sMimeTypes.FindMimeType(type);
|
||
if (mapper == NULL)
|
||
{
|
||
mapper = new CMimeMapper(CMimeMapper::Plugin, mimeType, "", extensions, '????', '????');
|
||
ThrowIfNil_(mapper);
|
||
mapper->SetPluginName(fPluginName);
|
||
mapper->SetDescription(description);
|
||
CPrefs::sMimeTypes.InsertItemsAt(1, LArray::index_Last, &mapper);
|
||
CPrefs::SetModified();
|
||
mapper->WriteMimePrefs(); // convert mapper to xp prefs
|
||
}
|
||
else if (mapper->FromOldPrefs())
|
||
{
|
||
mapper->SetPluginName(fPluginName);
|
||
mapper->SetExtensions(extensions);
|
||
mapper->SetDescription(description);
|
||
mapper->SetLoadAction(CMimeMapper::Plugin);
|
||
CPrefs::SetModified();
|
||
mapper->WriteMimePrefs(); // convert mapper to xp prefs
|
||
}
|
||
else if (mapper->LatentPlugin())
|
||
{
|
||
XP_ASSERT(mapper->GetLoadAction() == CMimeMapper::Unknown);
|
||
mapper->SetLoadAction(CMimeMapper::Plugin);
|
||
CPrefs::SetModified();
|
||
}
|
||
else
|
||
{
|
||
//
|
||
// Only update the description if (a) there<72>s a description
|
||
// from the plug-in itself (as opposed to a default description),
|
||
// and (b) the current description is blank (we don<6F>t want to
|
||
// overwrite a user-edited description).
|
||
//
|
||
if (gotDescription && mapper->GetDescription() == "")
|
||
{
|
||
mapper->SetDescription(description);
|
||
CPrefs::SetModified();
|
||
}
|
||
}
|
||
|
||
// Now we know whether the plug-in should be enabled or not
|
||
Boolean enabled = ((mapper->GetLoadAction() == CMimeMapper::Plugin) &&
|
||
(fPluginName == mapper->GetPluginName()));
|
||
NPL_RegisterPluginType(type, (char*) mapper->GetExtensions(), (char*) mapper->GetDescription(), NULL, this, enabled);
|
||
}
|
||
|
||
fFile->CloseResourceFork();
|
||
|
||
}
|
||
Catch_(inErr)
|
||
{
|
||
if (fFile != NULL)
|
||
fFile->CloseResourceFork();
|
||
|
||
}
|
||
EndCatch_;
|
||
|
||
ResetPlugFuncTable();
|
||
|
||
// Link us into the global list of handlers
|
||
fNextHandler = CPluginHandler::sHandlerList;
|
||
CPluginHandler::sHandlerList = this;
|
||
}
|
||
|
||
|
||
CPluginHandler::~CPluginHandler() // This code never gets called
|
||
{
|
||
// CloseCodeResource();
|
||
|
||
if (fFile)
|
||
delete fFile;
|
||
|
||
if (this == CPluginHandler::sHandlerList)
|
||
CPluginHandler::sHandlerList = NULL;
|
||
else
|
||
{
|
||
CPluginHandler* handler = CPluginHandler::sHandlerList;
|
||
while (handler != NULL)
|
||
{
|
||
if (this == handler->fNextHandler)
|
||
{
|
||
handler->fNextHandler = this->fNextHandler;
|
||
break;
|
||
}
|
||
handler = handler->fNextHandler;
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
void CPluginHandler::ResetPlugFuncTable()
|
||
{
|
||
fMainEntryFunc = NULL;
|
||
fUnloadFunc = NULL;
|
||
memset(&fPluginFuncs, 0, sizeof(NPPluginFuncs));
|
||
}
|
||
|
||
|
||
NPPluginFuncs * CPluginHandler::LoadPlugin(NPNetscapeFuncs * funcs, _np_handle* handle)
|
||
{
|
||
// XXX Needs to be fixed for C++ Plugin API
|
||
OSErr err = InitCodeResource(funcs, handle);
|
||
if (err == noErr)
|
||
return &fPluginFuncs;
|
||
|
||
return NULL;
|
||
}
|
||
|
||
OSErr CPluginHandler::InitCodeResource(NPNetscapeFuncs* funcs, _np_handle* handle)
|
||
{
|
||
fRefCount++;
|
||
|
||
if (fCode != NULL || fLibrary != 0) // Already loaded
|
||
return noErr;
|
||
|
||
OSErr err = noErr;
|
||
#ifdef DEBUG
|
||
EDebugAction oldThrow = UDebugging::gDebugThrow;
|
||
EDebugAction oldSignal = UDebugging::gDebugSignal;
|
||
UDebugging::gDebugThrow = debugAction_Nothing;
|
||
UDebugging::gDebugSignal = debugAction_Nothing;
|
||
#endif
|
||
Try_
|
||
{
|
||
OpenPluginResourceFork(fsRdWrPerm);
|
||
Try_
|
||
{ // PPC initialization
|
||
|
||
if (!UEnvironment::HasGestaltAttribute(gestaltCFMAttr, gestaltCFMPresent))
|
||
Throw_((OSErr)cfragNoLibraryErr); // No CFM
|
||
|
||
FSSpec fileSpec;
|
||
fFile->GetSpecifier(fileSpec);
|
||
|
||
char* cFullPath = CFileMgr::PathNameFromFSSpec(fileSpec, TRUE);
|
||
ThrowIfNil_(cFullPath);
|
||
|
||
fLibrary = PR_LoadLibrary(cFullPath);
|
||
ThrowIfNil_(fLibrary);
|
||
|
||
// PCB: Let's factor this into an XP function, please!
|
||
nsFactoryProc nsGetFactory = (nsFactoryProc) PR_FindSymbol(fLibrary, "NSGetFactory");
|
||
if (nsGetFactory != NULL) {
|
||
nsresult res = NS_OK;
|
||
if (thePluginManager == NULL) {
|
||
// For now, create the plugin manager on demand.
|
||
static NS_DEFINE_IID(kIPluginManagerIID, NS_IPLUGINMANAGER_IID);
|
||
res = nsPluginManager::Create(NULL, kIPluginManagerIID, (void**)&thePluginManager);
|
||
ThrowIf_(res != NS_OK || thePluginManager == NULL);
|
||
}
|
||
static NS_DEFINE_IID(kIPluginIID, NS_IPLUGIN_IID);
|
||
nsIPlugin* plugin = NULL;
|
||
res = nsGetFactory(kIPluginIID, (nsIFactory**)&plugin);
|
||
ThrowIf_(res != NS_OK || plugin == NULL);
|
||
// beard: establish the primary reference.
|
||
plugin->AddRef();
|
||
res = plugin->Initialize((nsIPluginManager2*)thePluginManager);
|
||
ThrowIf_(res != NS_OK);
|
||
handle->userPlugin = plugin;
|
||
} else {
|
||
fMainEntryFunc = (NPP_MainEntryUPP) PR_FindSymbol(fLibrary, "mainRD");
|
||
ThrowIfNil_(fMainEntryFunc);
|
||
}
|
||
}
|
||
Catch_(inErr)
|
||
{ // 68K if PPC fails
|
||
fLibrary = NULL; // No PPC
|
||
fCode = Get1Resource(emPluginFile, 128);
|
||
ThrowIfNil_(fCode);
|
||
::MoveHHi(fCode);
|
||
::HNoPurge(fCode);
|
||
::HLock(fCode);
|
||
|
||
//get the address of main and typecast it into a MainEntryProcUPP
|
||
fMainEntryFunc = (NPP_MainEntryUPP)(*fCode);
|
||
} EndCatch_
|
||
|
||
if (fMainEntryFunc != NULL) {
|
||
fPluginFuncs.version = funcs->version;
|
||
fPluginFuncs.size = sizeof(NPPluginFuncs);
|
||
err = CallNPP_MainEntryProc(fMainEntryFunc, funcs, &fPluginFuncs, &fUnloadFunc);
|
||
ThrowIfOSErr_(err);
|
||
if ((fPluginFuncs.version >> 8) < NP_VERSION_MAJOR)
|
||
Throw_((OSErr)NPERR_INCOMPATIBLE_VERSION_ERROR);
|
||
}
|
||
}
|
||
Catch_(inErr)
|
||
{
|
||
CloseCodeResource();
|
||
err = inErr;
|
||
}
|
||
EndCatch_
|
||
CPrefs::UseApplicationResFile(); // Revert the resource chain
|
||
#ifdef DEBUG
|
||
UDebugging::gDebugThrow = oldThrow;
|
||
UDebugging::gDebugSignal = oldSignal;
|
||
#endif
|
||
return err;
|
||
}
|
||
|
||
// Dispose of the code
|
||
void CPluginHandler::CloseCodeResource(_np_handle* handle)
|
||
{
|
||
// Already unloaded?
|
||
if (fRefCount == 0)
|
||
return;
|
||
|
||
// If there are still outstanding references, don't unload yet
|
||
fRefCount--;
|
||
if (fRefCount > 0)
|
||
return;
|
||
|
||
if (handle != NULL) {
|
||
nsIPlugin* userPlugin = handle->userPlugin;
|
||
if (userPlugin != NULL) {
|
||
userPlugin->Release();
|
||
handle->userPlugin = NULL;
|
||
}
|
||
} else
|
||
if (fUnloadFunc != NULL)
|
||
CallNPP_ShutdownProc(fUnloadFunc);
|
||
|
||
// Dispose of the code
|
||
// 68K, just release the resource
|
||
if (fCode != NULL)
|
||
{
|
||
::HUnlock(fCode);
|
||
::HPurge(fCode);
|
||
::ReleaseResource(fCode);
|
||
fCode = NULL;
|
||
}
|
||
// PPC, close the connections
|
||
if (fLibrary != NULL)
|
||
{
|
||
int err = PR_UnloadLibrary(fLibrary);
|
||
Assert_(err == 0);
|
||
fLibrary = NULL;
|
||
}
|
||
|
||
ResetPlugFuncTable();
|
||
|
||
Try_
|
||
{
|
||
fFile->CloseResourceFork();
|
||
}
|
||
Catch_(inErr){} EndCatch_
|
||
Try_
|
||
{
|
||
fFile->CloseDataFork();
|
||
}
|
||
Catch_(inErr){} EndCatch_
|
||
}
|
||
|
||
|
||
typedef struct ResourceMapEntry ResourceMapEntry, **ResourceMapHandle;
|
||
|
||
// See More Macintosh Toolbox, pp. 1-122, 1-123.
|
||
#if PRAGMA_ALIGN_SUPPORTED
|
||
#pragma options align=mac68k
|
||
#endif
|
||
struct ResourceMapEntry
|
||
{
|
||
UInt32 dataOffset;
|
||
UInt32 mapOffset;
|
||
UInt32 dataLength;
|
||
UInt32 mapLength;
|
||
ResourceMapHandle nextMap;
|
||
UInt16 refNum;
|
||
};
|
||
#if PRAGMA_ALIGN_SUPPORTED
|
||
#pragma options align=reset
|
||
#endif
|
||
|
||
//
|
||
// Open the plug-in<69>s resource fork BELOW the the application<6F>s
|
||
// resource fork. If we just opened the plug-in above the
|
||
// application but set the current res file to the app, the
|
||
// plug-in will be made current by the Resource Manager if the
|
||
// current res file is closed, which can happen when we close
|
||
// our prefs file after writing something to it. Once the plug-
|
||
// in is the current res file, if there are any resource conflicts
|
||
// between the two we<77>ll get the plug-in<69>s resource instead of
|
||
// ours, causing woe.
|
||
//
|
||
void CPluginHandler::OpenPluginResourceFork(Int16 inPrivileges)
|
||
{
|
||
Try_
|
||
{
|
||
Int16 plugRef = fFile->OpenResourceFork(inPrivileges); // Open normally
|
||
|
||
// The plug-in should now be at the top of the chain
|
||
ResourceMapHandle plugMap = (ResourceMapHandle) LMGetTopMapHndl();
|
||
ThrowIf_((**plugMap).refNum != plugRef);
|
||
|
||
// Search down the chain to find the app<70>s map
|
||
short appRef = LMGetCurApRefNum();
|
||
ResourceMapHandle appMap = (ResourceMapHandle) LMGetTopMapHndl();
|
||
while (appMap && (**appMap).refNum != appRef)
|
||
appMap = (**appMap).nextMap;
|
||
ThrowIfNil_(appMap);
|
||
|
||
// Remove the plug-in from the top of the chain
|
||
ResourceMapHandle newTop = (**plugMap).nextMap;
|
||
ThrowIfNil_(newTop);
|
||
LMSetTopMapHndl((Handle)newTop);
|
||
|
||
// Re-insert the plug-in below the application
|
||
(**plugMap).nextMap = (**appMap).nextMap;
|
||
(**appMap).nextMap = plugMap;
|
||
}
|
||
Catch_(inErr)
|
||
{
|
||
}
|
||
EndCatch_
|
||
}
|
||
|
||
|
||
|
||
|
||
|
||
void RegisterPluginsInFolder(FSSpec folder);
|
||
// Recursive registration of all plugins
|
||
void RegisterPluginsInFolder(FSSpec folder)
|
||
{
|
||
// find all the files that are plugins
|
||
CFileIter iter(folder);
|
||
FSSpec plugFile;
|
||
FInfo finderInfo;
|
||
Boolean isFolder;
|
||
while (iter.Next(plugFile, finderInfo, isFolder))
|
||
{
|
||
if (isFolder)
|
||
RegisterPluginsInFolder(plugFile);
|
||
else if (finderInfo.fdType == emPluginFile)
|
||
{
|
||
//
|
||
// Check the handlers we already have registered against
|
||
// the given file spec. We don<6F>t want to redundantly
|
||
// create handlers for the same plugin file.
|
||
//
|
||
if (CPluginHandler::CheckExistingHandlers(plugFile))
|
||
{
|
||
Try_
|
||
{
|
||
CPluginHandler* plug = new CPluginHandler(plugFile);
|
||
}
|
||
Catch_(inErr){}
|
||
EndCatch_
|
||
}
|
||
}
|
||
#ifdef EDITOR
|
||
else {
|
||
unsigned char *name = &plugFile.name[0];
|
||
int len = name[0];
|
||
|
||
/* This checks to see if the name starts with cp and ends in '.zip' or '.jar'.
|
||
*/
|
||
if (len >= 5) {
|
||
if ((name[1] == 'c' || name[1] == 'C')
|
||
&& (name[2] == 'p' || name[2] == 'P')
|
||
&& (name[len - 3] == '.')
|
||
&& ((name[len - 2] == 'z' || name[len - 2] == 'Z')
|
||
&& (name[len - 1] == 'i' || name[len - 1] == 'I')
|
||
&& (name[len - 0] == 'p' || name[len - 0] == 'P'))
|
||
|| ((name[len - 2] == 'j' || name[len - 2] == 'J')
|
||
&& (name[len - 1] == 'a' || name[len - 1] == 'A')
|
||
&& (name[len - 0] == 'r' || name[len - 0] == 'R'))) {
|
||
char *cFullPath = CFileMgr::PathNameFromFSSpec( plugFile, TRUE );
|
||
ThrowIfNil_(cFullPath);
|
||
char* cUnixFullPath = CFileMgr::EncodeMacPath(cFullPath); // Frees cFullPath
|
||
ThrowIfNil_(cUnixFullPath);
|
||
(void) NET_UnEscape(cUnixFullPath);
|
||
|
||
EDT_RegisterPlugin(cUnixFullPath);
|
||
XP_FREE(cUnixFullPath);
|
||
}
|
||
}
|
||
}
|
||
#endif // EDITOR
|
||
}
|
||
|
||
//
|
||
// Tell Java to look in this directory for class files
|
||
// so LiveConnect-enabled plug-ins can store their classes
|
||
// with the plug-in.
|
||
//
|
||
Try_
|
||
{
|
||
char* cFullPath = CFileMgr::PathNameFromFSSpec(folder, TRUE);
|
||
ThrowIfNil_(cFullPath);
|
||
char* cUnixFullPath = CFileMgr::EncodeMacPath(cFullPath); // Frees cFullPath
|
||
ThrowIfNil_(cUnixFullPath);
|
||
(void) NET_UnEscape(cUnixFullPath);
|
||
|
||
#if defined(JAVA)
|
||
// Tell Java about this path name
|
||
LJ_AddToClassPath(cUnixFullPath);
|
||
#elif defined(OJI)
|
||
// What, tell the current Java plugin about this class path?
|
||
#endif
|
||
XP_FREE(cUnixFullPath);
|
||
}
|
||
Catch_(inErr) {}
|
||
EndCatch_
|
||
}
|
||
|
||
//
|
||
// Default handler registered below for formats FO_CACHE_AND_EMBED and
|
||
// FO_CACHE, across all types. This handler recovers the pointer to
|
||
// our CPluginView and tells it that it does not have a valid plugin
|
||
// instance.
|
||
//
|
||
NET_StreamClass* EmbedDefault(
|
||
int format_out, void* registration, URL_Struct* request, MWContext* context);
|
||
NET_StreamClass* EmbedDefault(
|
||
int /*format_out*/, void* /*registration*/, URL_Struct* request, MWContext*)
|
||
{
|
||
if (request != NULL)
|
||
{
|
||
NPEmbeddedApp* fe_data = (NPEmbeddedApp*) request->fe_data;
|
||
if (fe_data != NULL)
|
||
{
|
||
CPluginView* plugin = (CPluginView*) fe_data->fe_data;
|
||
if (plugin != NULL)
|
||
plugin->SetBrokenPlugin();
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
/* Returns the plugin folder spec */
|
||
OSErr FindPluginFolder(FSSpec * plugFolder, Boolean create);
|
||
OSErr FindPluginFolder(FSSpec * plugFolder, Boolean create)
|
||
{
|
||
FSSpec netscapeSpec = CPrefs::GetFolderSpec(CPrefs::NetscapeFolder);
|
||
long netscape_dirID;
|
||
|
||
|
||
OSErr err;
|
||
if ( (err=CFileMgr::GetFolderID(netscapeSpec, netscape_dirID)) == noErr )
|
||
{
|
||
#ifndef PLUGIN_FOLDER_NAME_MUST_BE_MOVED_TO_A_RESOURCE
|
||
/*
|
||
Yes! It's a bugus preprocessor symbol, but it got your attention, didn't it?
|
||
|
||
For localization, the plugin folder name should be moved to a resource, however there is no reported
|
||
bug yet (and we're currently under change control).
|
||
|
||
***Move only the preferred name into a resource. Leave the old name as a constant string in the source
|
||
(since the old name will not have been localized on any users disk).***
|
||
|
||
In the meantime...
|
||
*/
|
||
|
||
Str255 pluginFolderName = "\pPlug-ins";
|
||
#else
|
||
// The preferred (localized) name of the plugins folder is in a resource...
|
||
Str255 pluginFolderName;
|
||
GetIndString(pluginFolderName, ..., ...);
|
||
#endif
|
||
|
||
|
||
FSSpec oldNameSpec;
|
||
Boolean isFolder, wasAliased;
|
||
|
||
// first look for the preferences folder with the preferred name
|
||
if ( ((err=FSMakeFSSpec(netscapeSpec.vRefNum, netscape_dirID, pluginFolderName, plugFolder)) == noErr) // ...if we made the FSSpec ok
|
||
&& ((err=ResolveAliasFile(plugFolder, true, &isFolder, &wasAliased)) == noErr) ) // ...and it leads to something
|
||
{
|
||
// the plugins folder already exists as "Plug-ins", nothing else to do
|
||
}
|
||
|
||
// else, try the old name (using |oldNameSpec|, so that if not found, I can create a folder from the preferred spec created above)
|
||
else if ( ((err=FSMakeFSSpec(netscapeSpec.vRefNum, netscape_dirID, "\pPlugins", &oldNameSpec)) == noErr) // ...if we made the FSSpec ok
|
||
&& ((err=ResolveAliasFile(&oldNameSpec, true, &isFolder, &wasAliased)) == noErr) ) // ...and it leads to something
|
||
{
|
||
// the plugins folder already exists as [deprecated] "Plugins", copy the spec we used to learn that to the caller
|
||
FSMakeFSSpec(oldNameSpec.vRefNum, oldNameSpec.parID, oldNameSpec.name, plugFolder);
|
||
}
|
||
|
||
// otherwise, we may need to create it
|
||
else if ( create )
|
||
{
|
||
long created_dirID;
|
||
err = FSpDirCreate(plugFolder, smSystemScript, &created_dirID);
|
||
}
|
||
}
|
||
|
||
return err;
|
||
}
|
||
|
||
// *************************************************************************************
|
||
//
|
||
// XP interface methods
|
||
//
|
||
// *************************************************************************************
|
||
|
||
void FE_RegisterPlugins();
|
||
void FE_RegisterPlugins()
|
||
{
|
||
//
|
||
// Register a wildcard handler for "embed" types before we scan the
|
||
// plugins folder -- that way, if a "null plugin" is found that
|
||
// also registers "*"/FO_EMBED, it will be registered later than this
|
||
// handler and thus take precendence.
|
||
//
|
||
NET_RegisterContentTypeConverter("*", FO_EMBED, NULL, EmbedDefault);
|
||
|
||
OSErr err;
|
||
FSSpec plugFolder;
|
||
|
||
if (!IsThisKeyDown(kOptionKey)) // Skip loading plugins if option key is down
|
||
err = FindPluginFolder(&plugFolder, false);
|
||
else
|
||
err = -1;
|
||
|
||
if (err != noErr)
|
||
{
|
||
CFrontApp::SplashProgress(GetPString(MAC_NO_PLUGIN));
|
||
return;
|
||
}
|
||
else
|
||
{
|
||
CFrontApp::SplashProgress(GetPString(MAC_REGISTER_PLUGINS));
|
||
RegisterPluginsInFolder(plugFolder);
|
||
}
|
||
|
||
//
|
||
// Now that all plug-ins have been registered, look through the MIME table
|
||
// for types that are assigned to non-existant plug-ins or plug-in types,
|
||
// and change all these types to use "Unknown".
|
||
//
|
||
LArrayIterator iterator(CPrefs::sMimeTypes);
|
||
CMimeMapper* mapper;
|
||
while (iterator.Next(&mapper))
|
||
{
|
||
if (mapper->GetLoadAction() == CMimeMapper::Plugin) // Handled by plug-in?
|
||
{
|
||
Boolean foundType = false;
|
||
char* otherPluginName = NULL;
|
||
|
||
// Look for the desired plug-in
|
||
CStr255 mapperName = mapper->GetPluginName();
|
||
NPReference plugin = NPRefFromStart;
|
||
char* name;
|
||
while (NPL_IteratePluginFiles(&plugin, &name, NULL, NULL))
|
||
{
|
||
// Look for the desired type
|
||
CStr255 mapperMime = mapper->GetMimeName();
|
||
NPReference mimetype = NPRefFromStart;
|
||
char* type;
|
||
while (NPL_IteratePluginTypes(&mimetype, plugin, &type, NULL, NULL, NULL))
|
||
{
|
||
if (mapperMime == type)
|
||
{
|
||
if (mapperName != name)
|
||
otherPluginName = name;
|
||
else
|
||
foundType = true;
|
||
break;
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
if (!foundType) // No plug-in, or no type?
|
||
{
|
||
if (otherPluginName)
|
||
{
|
||
void* pdesc = GetPluginDesc(otherPluginName);
|
||
if (pdesc)
|
||
NPL_EnablePluginType((char*)mapper->GetMimeName(), pdesc, TRUE);
|
||
mapper->SetPluginName(otherPluginName);
|
||
CPrefs::SetModified();
|
||
}
|
||
else
|
||
{
|
||
mapper->SetLatentPlugin(); // Mark the plug-in as <20>disabled because missing<6E>
|
||
CPrefs::SetModified(); // The prefs have changed
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
NPPluginFuncs * FE_LoadPlugin(void *plugin, NPNetscapeFuncs * funcs, struct _np_handle* handle)
|
||
{
|
||
return ((CPluginHandler*)plugin)->LoadPlugin(funcs, handle);
|
||
}
|
||
|
||
void FE_UnloadPlugin(void *plugin, struct _np_handle* handle)
|
||
{
|
||
((CPluginHandler*)plugin)->CloseCodeResource(handle);
|
||
}
|
||
|
||
//
|
||
// This exit routine is called when an embed stream completes.
|
||
// We use that opportunity to see if something when wrong when
|
||
// creating the initial stream for the plug-in so we can
|
||
// display some helpful UI.
|
||
//
|
||
void FE_EmbedURLExit(URL_Struct* /*urls*/, int /*status*/, MWContext* /*cx*/)
|
||
{
|
||
// bing: Don't do anything here until we figure out a
|
||
}
|
||
|
||
|
||
//
|
||
// This code is called by npn_status, which is called by the plug-in.
|
||
// The plug-in may have manipulated the port before calling us, so
|
||
// we have to assume that we're out of focus so we'll draw in the
|
||
// right place. We also need to save and restore the entire port
|
||
// state so the plug-in's port settings are trashed.
|
||
//
|
||
void FE_PluginProgress(MWContext* cx, const char* message)
|
||
{
|
||
GrafPtr currentPort;
|
||
GetPort(¤tPort);
|
||
StColorPortState portState(currentPort);
|
||
portState.Save(currentPort);
|
||
StUseResFile resFile(LMGetCurApRefNum());
|
||
|
||
LView::OutOfFocus(nil); // Make sure FE_Progress focuses the caption
|
||
FE_Progress(cx, message);
|
||
LView::OutOfFocus(nil); // portState.Restore will screw up the focus again
|
||
|
||
portState.Restore();
|
||
}
|
||
|
||
|
||
//
|
||
// See comments in npglue.c in np_geturlinternal.
|
||
//
|
||
void FE_ResetRefreshURLTimer(MWContext* )
|
||
{
|
||
Assert_(false);
|
||
// if (NETSCAPEVIEW(context))
|
||
// NETSCAPEVIEW(context)->ResetRefreshURLTimer();
|
||
}
|
||
|
||
// A generic way to query information. Nothing to do now.
|
||
NPError FE_PluginGetValue(MWContext *, NPEmbeddedApp *, NPNVariable ,
|
||
void */*r_value*/)
|
||
{
|
||
return NPERR_NO_ERROR;
|
||
}
|
||
|
||
//
|
||
// Rather than having to scan an explicit list of windows each time an event
|
||
// comes in, why not use a sub-class of LWindow, and let PowerPlant do the work
|
||
// for us?
|
||
//
|
||
|
||
#pragma mark ### CPluginWindow ###
|
||
|
||
class CPluginWindow : public LWindow, public LPeriodical {
|
||
public:
|
||
CPluginWindow(nsIEventHandler* eventHandler, WindowRef window);
|
||
virtual ~CPluginWindow();
|
||
|
||
virtual void HandleClick(const EventRecord& inMacEvent, Int16 inPart);
|
||
virtual void EventMouseUp(const EventRecord &inMacEvent);
|
||
virtual Boolean ObeyCommand(CommandT inCommand, void *ioParam);
|
||
virtual Boolean HandleKeyPress(const EventRecord& inKeyEvent);
|
||
virtual void DrawSelf();
|
||
virtual void SpendTime(const EventRecord& inMacEvent);
|
||
virtual void ActivateSelf();
|
||
virtual void DeactivateSelf();
|
||
virtual void AdjustCursorSelf(Point inPortPt, const EventRecord& inMacEvent);
|
||
|
||
Boolean IsPluginCommand(CommandT inCommand);
|
||
Boolean PassPluginEvent(EventRecord& event);
|
||
|
||
private:
|
||
nsIEventHandler* mEventHandler;
|
||
SInt16 mKind;
|
||
};
|
||
|
||
void FE_RegisterWindow(nsIEventHandler* handler, void* window)
|
||
{
|
||
#if 1
|
||
LCommander::LCommander::SetDefaultCommander(LCommander::GetTopCommander());
|
||
CPluginWindow* pluginWindow = new CPluginWindow(handler, WindowRef(window));
|
||
XP_ASSERT(pluginWindow != NULL);
|
||
if (pluginWindow != NULL) {
|
||
pluginWindow->Show();
|
||
pluginWindow->Select();
|
||
}
|
||
#else
|
||
((CPluginView*)plugin)->RegisterWindow(window);
|
||
#endif
|
||
}
|
||
|
||
void FE_UnregisterWindow(nsIEventHandler* handler, void* window)
|
||
{
|
||
#if 1
|
||
// Toss the pluginWindow itself.
|
||
LWindow* pluginWindow = LWindow::FetchWindowObject(WindowPtr(window));
|
||
if (pluginWindow != NULL) {
|
||
// Hide the window.
|
||
pluginWindow->Hide();
|
||
// Notify PowerPlant that the window is no longer active.
|
||
// pluginWindow->Deactivate();
|
||
delete pluginWindow;
|
||
}
|
||
#else
|
||
((CPluginView*)plugin)->UnregisterWindow(window);
|
||
#endif
|
||
}
|
||
|
||
#if 0
|
||
SInt16 FE_AllocateMenuID(void *plugin, XP_Bool isSubmenu)
|
||
{
|
||
return ((CPluginView*)plugin)->AllocateMenuID(isSubmenu);
|
||
}
|
||
#endif
|
||
|
||
CPluginWindow::CPluginWindow(nsIEventHandler* eventHandler, WindowRef window)
|
||
{
|
||
mEventHandler = eventHandler;
|
||
mMacWindowP = window;
|
||
|
||
// The following is cribbed from one of the LWindow constructors.
|
||
|
||
// "bless" the plugin window so it will be considered to be a first-class PowerPlant window.
|
||
mKind = ::GetWindowKind(window);
|
||
::SetWindowKind(window, PP_Window_Kind);
|
||
::SetWRefCon(window, long(this));
|
||
|
||
// Set some default attributes.
|
||
SetAttribute(windAttr_CloseBox | windAttr_TitleBar | windAttr_Resizable
|
||
| windAttr_SizeBox | windAttr_Targetable | windAttr_Enabled);
|
||
|
||
// Window Frame and Image are the same as its portRect.
|
||
short width = mMacWindowP->portRect.right - mMacWindowP->portRect.left;
|
||
short height = mMacWindowP->portRect.bottom - mMacWindowP->portRect.top;
|
||
|
||
ResizeFrameTo(width, height, false);
|
||
ResizeImageTo(width, height, false);
|
||
|
||
CalcRevealedRect();
|
||
|
||
// Initial size and location are the "user" state for zooming.
|
||
CalcPortFrameRect(mUserBounds);
|
||
PortToGlobalPoint(topLeft(mUserBounds));
|
||
PortToGlobalPoint(botRight(mUserBounds));
|
||
|
||
mVisible = triState_Off;
|
||
mActive = triState_Off;
|
||
mEnabled = triState_Off;
|
||
if (HasAttribute(windAttr_Enabled)) {
|
||
mEnabled = triState_On;
|
||
}
|
||
|
||
FocusDraw();
|
||
::GetForeColor(&mForeColor);
|
||
::GetBackColor(&mBackColor);
|
||
|
||
StartIdling();
|
||
}
|
||
|
||
CPluginWindow::~CPluginWindow()
|
||
{
|
||
// prevent the LWindow destructor from clobbering the window.
|
||
if (mMacWindowP != NULL) {
|
||
WindowPtr window = mMacWindowP;
|
||
if (IsWindowVisible(window))
|
||
HideSelf();
|
||
|
||
// Restore kind and refCon to original values.
|
||
::SetWindowKind(window, mKind);
|
||
::SetWRefCon(window, 0);
|
||
|
||
mMacWindowP = NULL;
|
||
}
|
||
}
|
||
|
||
void CPluginWindow::HandleClick(const EventRecord& inMacEvent, Int16 inPart)
|
||
{
|
||
EventRecord mouseEvent = inMacEvent;
|
||
if (!PassPluginEvent(mouseEvent))
|
||
LWindow::HandleClick(inMacEvent, inPart);
|
||
}
|
||
|
||
void CPluginWindow::EventMouseUp(const EventRecord& inMouseUp)
|
||
{
|
||
EventRecord mouseEvent = inMouseUp;
|
||
PassPluginEvent(mouseEvent);
|
||
}
|
||
|
||
Boolean CPluginWindow::ObeyCommand(CommandT inCommand, void *ioParam)
|
||
{
|
||
if (IsPluginCommand(inCommand)) {
|
||
EventRecord menuEvent;
|
||
::OSEventAvail(0, &menuEvent);
|
||
menuEvent.what = nsPluginEventType_MenuCommandEvent;
|
||
menuEvent.message = -inCommand; // PowerPlant encodes a raw menu selection as the negation of the selection.
|
||
return PassPluginEvent(menuEvent);
|
||
}
|
||
return LWindow::ObeyCommand(inCommand, ioParam);
|
||
}
|
||
|
||
Boolean CPluginWindow::HandleKeyPress(const EventRecord& inKeyEvent)
|
||
{
|
||
EventRecord keyEvent = inKeyEvent;
|
||
return PassPluginEvent(keyEvent);
|
||
}
|
||
|
||
void CPluginWindow::DrawSelf()
|
||
{
|
||
EventRecord updateEvent;
|
||
::OSEventAvail(0, &updateEvent);
|
||
updateEvent.what = updateEvt;
|
||
updateEvent.message = UInt32(mMacWindowP);
|
||
PassPluginEvent(updateEvent);
|
||
}
|
||
|
||
void CPluginWindow::SpendTime(const EventRecord& inMacEvent)
|
||
{
|
||
// Need to poll various states, because the plugin can change things like
|
||
// the window's visibility, size, etc.
|
||
|
||
// Put the visible state in synch with the window's visibility.
|
||
mVisible = (IsWindowVisible(mMacWindowP) ? triState_On : triState_Off);
|
||
|
||
// Make sure the window's size hasn't changed (what about location?)
|
||
short width = mMacWindowP->portRect.right - mMacWindowP->portRect.left;
|
||
short height = mMacWindowP->portRect.bottom - mMacWindowP->portRect.top;
|
||
if (mFrameSize.width != width || mFrameSize.height != height) {
|
||
ResizeFrameTo(width, height, false);
|
||
ResizeImageTo(width, height, false);
|
||
CalcRevealedRect();
|
||
}
|
||
|
||
EventRecord macEvent = inMacEvent;
|
||
PassPluginEvent(macEvent);
|
||
|
||
//
|
||
// If we<77>re in SpendTime because of a non-null event, send a
|
||
// null event too. Some plug-ins (e.g. Shockwave) rely on null
|
||
// events for animation, so it doesn<73>t matter if we<77>re giving
|
||
// them lots of time with mouseMoved or other events -- if they
|
||
// don<6F>t get null events, they don<6F>t animate fast.
|
||
//
|
||
if (macEvent.what != nullEvent) {
|
||
macEvent.what = nullEvent;
|
||
PassPluginEvent(macEvent);
|
||
}
|
||
}
|
||
|
||
void CPluginWindow::ActivateSelf()
|
||
{
|
||
LWindow::ActivateSelf();
|
||
|
||
EventRecord activateEvent;
|
||
::OSEventAvail(0, &activateEvent);
|
||
activateEvent.what = activateEvt;
|
||
activateEvent.modifiers |= activeFlag;
|
||
activateEvent.message = UInt32(mMacWindowP);
|
||
PassPluginEvent(activateEvent);
|
||
}
|
||
|
||
|
||
void CPluginWindow::DeactivateSelf()
|
||
{
|
||
LWindow::DeactivateSelf();
|
||
|
||
EventRecord activateEvent;
|
||
::OSEventAvail(0, &activateEvent);
|
||
activateEvent.what = activateEvt;
|
||
activateEvent.modifiers &= ~activeFlag;
|
||
activateEvent.message = UInt32(mMacWindowP);
|
||
PassPluginEvent(activateEvent);
|
||
}
|
||
|
||
void CPluginWindow::AdjustCursorSelf(Point inPortPt, const EventRecord& inMacEvent)
|
||
{
|
||
EventRecord cursorEvent = inMacEvent;
|
||
cursorEvent.what = nsPluginEventType_AdjustCursorEvent;
|
||
if (!PassPluginEvent(cursorEvent))
|
||
LWindow::AdjustCursorSelf(inPortPt, inMacEvent);
|
||
}
|
||
|
||
Boolean CPluginWindow::IsPluginCommand(CommandT inCommand)
|
||
{
|
||
#if 1
|
||
// Since only one plugin can have menus in the menu bar at a time,
|
||
// the test only checks to see if this plugin has any menus, and
|
||
// whether the command is synthetic and is from one of the plugin's menus.
|
||
if (thePluginManager != NULL) {
|
||
short menuID, menuItem;
|
||
if (LCommander::IsSyntheticCommand(inCommand, menuID, menuItem)) {
|
||
PRBool hasAllocated = PR_FALSE;
|
||
if (thePluginManager->HasAllocatedMenuID(mEventHandler, menuID, &hasAllocated) == NS_OK)
|
||
return hasAllocated;
|
||
}
|
||
}
|
||
return false;
|
||
#else
|
||
return mPlugin->IsPluginCommand(inCommand);
|
||
#endif
|
||
}
|
||
|
||
Boolean CPluginWindow::PassPluginEvent(EventRecord& event)
|
||
{
|
||
#if 1
|
||
nsPluginEvent pluginEvent = { &event, mMacWindowP };
|
||
PRBool eventHandled = PR_FALSE;
|
||
mEventHandler->HandleEvent(&pluginEvent, &eventHandled);
|
||
return eventHandled;
|
||
#else
|
||
return mPlugin->PassWindowEvent(event, mMacWindowP))
|
||
#endif
|
||
}
|
||
|
||
|
||
// *************************************************************************************
|
||
//
|
||
// CPluginView methods
|
||
//
|
||
// *************************************************************************************
|
||
|
||
#pragma mark ### CPluginView ###
|
||
|
||
CPluginView* CPluginView::sPluginTarget = NULL;
|
||
LArray* CPluginView::sPluginList = NULL;
|
||
|
||
//
|
||
// This static method lets the caller broadcast a mac event to
|
||
// all existing plug-ins (regardless of context). It<49>s used by
|
||
// CFrontApp::EventSuspendResume to broadcast suspend and resume
|
||
// events to plug-ins.
|
||
//
|
||
void CPluginView::BroadcastPluginEvent(const EventRecord& event)
|
||
{
|
||
if (sPluginList != NULL)
|
||
{
|
||
EventRecord eventCopy = event; // event is const, but PassEvent isn<73>t
|
||
LArrayIterator iterator(*sPluginList);
|
||
CPluginView* plugin = NULL;
|
||
while (iterator.Next(&plugin))
|
||
(void) plugin->PassEvent(eventCopy);
|
||
}
|
||
}
|
||
|
||
// XXX The following two methods are obsolete -- CPluginWindow now does the work.
|
||
|
||
// This gets called for every event - a performance analysis/review would be good
|
||
Boolean CPluginView::PluginWindowEvent(const EventRecord& event)
|
||
{
|
||
WindowPtr hitWindow;
|
||
|
||
switch(event.what)
|
||
{
|
||
case mouseDown:
|
||
case mouseUp:
|
||
::FindWindow(event.where, &hitWindow);
|
||
break;
|
||
|
||
case autoKey:
|
||
case keyDown:
|
||
case keyUp:
|
||
hitWindow = ::FrontWindow();
|
||
break;
|
||
|
||
case activateEvt:
|
||
case updateEvt:
|
||
hitWindow = (WindowPtr) event.message;
|
||
break;
|
||
|
||
case nullEvent:
|
||
case diskEvt:
|
||
case osEvt:
|
||
case kHighLevelEvent:
|
||
default:
|
||
return false;
|
||
}
|
||
|
||
#if 1
|
||
// Determine which plugin owns this window.
|
||
Boolean isActivateEvent = (event.what == activateEvt && (event.modifiers & activeFlag));
|
||
CPluginView* owningPlugin = FindPlugin(hitWindow);
|
||
if (owningPlugin != NULL) {
|
||
EventRecord eventCopy = event;
|
||
return owningPlugin->PassWindowEvent(eventCopy, hitWindow);
|
||
}
|
||
#else
|
||
if (sPluginList != NULL) {
|
||
// iterate through each plugin instance
|
||
LArrayIterator pluginIterator(*sPluginList);
|
||
CPluginView* plugin = NULL;
|
||
while (pluginIterator.Next(&plugin)) {
|
||
if (plugin->fWindowList != NULL) {
|
||
// then iterate through each window for each instance
|
||
LArrayIterator windowIterator(*(plugin->fWindowList));
|
||
WindowPtr window = NULL;
|
||
while (windowIterator.Next(&window)) {
|
||
if (window == hitWindow) {
|
||
EventRecord eventCopy = event;
|
||
return plugin->PassWindowEvent(eventCopy, window);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
#endif
|
||
|
||
// we didn't find a match
|
||
return false;
|
||
}
|
||
|
||
// Determines which plugin owns the specified window.
|
||
|
||
CPluginView* CPluginView::FindPlugin(WindowPtr window)
|
||
{
|
||
// Make sure the window isn't a PowerPlant window.
|
||
LWindow* windowObj = LWindow::FetchWindowObject(window);
|
||
if (windowObj == NULL && sPluginList != NULL) {
|
||
// iterate through each plugin instance
|
||
LArrayIterator pluginIterator(*sPluginList);
|
||
CPluginView* plugin = NULL;
|
||
while (pluginIterator.Next(&plugin)) {
|
||
if (plugin->fWindowList != NULL) {
|
||
// then iterate through each window for each instance
|
||
LArrayIterator windowIterator(*(plugin->fWindowList));
|
||
WindowPtr pluginWindow = NULL;
|
||
while (windowIterator.Next(&pluginWindow)) {
|
||
if (window == pluginWindow)
|
||
return plugin;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
return NULL;
|
||
}
|
||
|
||
void CPluginView::RegisterWindow(void* window)
|
||
{
|
||
// Register the pluginWindow with PowerPlant.
|
||
|
||
// Set the default commander to the application, to limit the depth of the chain of command.
|
||
// I've seen this get ridiculously deep.
|
||
LCommander::LCommander::SetDefaultCommander(LCommander::GetTopCommander());
|
||
|
||
#if 0
|
||
CPluginWindow* pluginWindow = new CPluginWindow(this, WindowPtr(window));
|
||
|
||
if (fWindowList == NULL)
|
||
fWindowList = new LArray;
|
||
if (fWindowList != NULL)
|
||
fWindowList->InsertItemsAt(1, 0, &window);
|
||
#endif
|
||
}
|
||
|
||
void CPluginView::UnregisterWindow(void* window)
|
||
{
|
||
// Toss the pluginWindow itself.
|
||
LWindow* pluginWindow = LWindow::FetchWindowObject(WindowPtr(window));
|
||
if (pluginWindow != NULL) {
|
||
// Notify PowerPlant that the window is no longer active.
|
||
pluginWindow->Deactivate();
|
||
delete pluginWindow;
|
||
}
|
||
|
||
#if 0
|
||
if (fWindowList != NULL) {
|
||
Int32 index = fWindowList->FetchIndexOf(&window);
|
||
if (index > 0)
|
||
fWindowList->RemoveItemsAt(1, index);
|
||
|
||
if (fWindowList->GetCount() == 0) {
|
||
delete fWindowList;
|
||
fWindowList = NULL;
|
||
}
|
||
}
|
||
#endif
|
||
}
|
||
|
||
|
||
SInt16 CPluginView::AllocateMenuID(Boolean isSubmenu)
|
||
{
|
||
SInt16 menuID = LMenuSharingAttachment::AllocatePluginMenuID(isSubmenu);
|
||
|
||
if (fMenuList == NULL)
|
||
fMenuList = new TArray<SInt16>;
|
||
if (fMenuList != NULL)
|
||
fMenuList->AddItem(menuID);
|
||
|
||
return menuID;
|
||
}
|
||
|
||
Boolean CPluginView::IsPluginCommand(CommandT inCommand)
|
||
{
|
||
// Since only one plugin can have menus in the menu bar at a time,
|
||
// the test only checks to see if this plugin has any menus, and
|
||
// whether the command is synthetic and is from one of the plugin's menus.
|
||
if (fMenuList != NULL) {
|
||
short menuId, menuItem;
|
||
if (LCommander::IsSyntheticCommand(inCommand, menuId, menuItem)) {
|
||
TArray<SInt16>& menus = *fMenuList;
|
||
UInt32 count = menus.GetCount();
|
||
for (UInt32 i = count; i > 0; --i)
|
||
if (menus[i] == menuId)
|
||
return true;
|
||
}
|
||
}
|
||
return false;
|
||
}
|
||
|
||
Boolean CPluginView::PassWindowEvent(EventRecord& inEvent, WindowPtr window)
|
||
{
|
||
Boolean eventHandled = false;
|
||
if (fApp) {
|
||
eventHandled = NPL_HandleEvent(fApp, (NPEvent*)&inEvent, (void*) window);
|
||
}
|
||
return eventHandled;
|
||
}
|
||
|
||
CPluginView::CPluginView(LStream *inStream) : LView(inStream), LDragAndDrop(nil, this)
|
||
{
|
||
fApp = NULL;
|
||
fOriginalView = NULL;
|
||
fBrokenPlugin = false;
|
||
fPositioned = false;
|
||
fHidden = false;
|
||
fWindowed = true;
|
||
fBrokenIcon = NULL;
|
||
fIsPrinting = false;
|
||
fWindowList = NULL;
|
||
fMenuList = NULL;
|
||
|
||
//
|
||
// Add the new plug-in to a global list of all plug-ins.
|
||
//
|
||
if (sPluginList == NULL)
|
||
sPluginList = new LArray;
|
||
if (sPluginList != NULL)
|
||
sPluginList->InsertItemsAt(1, 0, &this);
|
||
|
||
|
||
//
|
||
// Can<61>t call ResetDrawRect yet because it needs a port
|
||
// from our superview, but we don<6F>t have a superview yet!
|
||
//
|
||
}
|
||
|
||
|
||
CPluginView::~CPluginView()
|
||
{
|
||
if (fBrokenIcon != NULL)
|
||
CIconList::ReturnIcon(fBrokenIcon);
|
||
|
||
//
|
||
// This static is parallel to LCommander::sTarget, but only for plug-ins.
|
||
// The LCommander destructor takes care of resetting the LCommander::sTarget,
|
||
// and so the CPluginView destructor should take care of the special plug-in target.
|
||
//
|
||
if (CPluginView::sPluginTarget == this)
|
||
CPluginView::sPluginTarget = NULL;
|
||
|
||
// we're assuming the plugin has already killed the windows themselves
|
||
if (fWindowList != NULL)
|
||
delete fWindowList;
|
||
|
||
// release the menu IDs used by this plugin?
|
||
if (fMenuList != NULL)
|
||
delete fMenuList;
|
||
|
||
//
|
||
// Remove the deleted plug-in from the global list of all plug-ins.
|
||
//
|
||
if (sPluginList != NULL) {
|
||
Int32 index = sPluginList->FetchIndexOf(&this);
|
||
if (index > 0)
|
||
sPluginList->RemoveItemsAt(1, index);
|
||
|
||
if (sPluginList->GetCount() == 0)
|
||
{
|
||
delete sPluginList;
|
||
sPluginList = NULL;
|
||
}
|
||
}
|
||
};
|
||
|
||
|
||
void CPluginView::EmbedSize(LO_EmbedStruct* embed_struct, SDimension16 hyperSize)
|
||
{
|
||
//
|
||
// If the plug-in is hidden, set the width and height to zero and
|
||
// set a flag indicating that we are hidden.
|
||
//
|
||
if (embed_struct->objTag.ele_attrmask & LO_ELE_HIDDEN)
|
||
{
|
||
embed_struct->objTag.width = 0;
|
||
embed_struct->objTag.height = 0;
|
||
fHidden = true;
|
||
Hide();
|
||
StartIdling(); // Visible plug-ins start idling in EmbedDisplay
|
||
}
|
||
|
||
//
|
||
// If the embed src is internal-external-plugin, the plugin is
|
||
// full-screen, and we should set up the plugin<69>s real width
|
||
// for layout since it doesn<73>t know how big to make it. Since a full-
|
||
// screen plugin should resize when its enclosing view (the hyperview)
|
||
// resizes, we bind the plugin view on all sides to its superview.
|
||
//
|
||
Boolean fullPage = false;
|
||
if (embed_struct->embed_src)
|
||
{
|
||
char* theURL;
|
||
PA_LOCK(theURL, char*, embed_struct->embed_src);
|
||
XP_ASSERT(theURL);
|
||
if (XP_STRCMP(theURL, "internal-external-plugin") == 0)
|
||
fullPage = true;
|
||
PA_UNLOCK(embed_struct->embed_src);
|
||
}
|
||
|
||
if (fullPage)
|
||
{
|
||
SBooleanRect binding = {true, true, true, true};
|
||
SetFrameBinding(binding);
|
||
|
||
embed_struct->objTag.width = hyperSize.width;
|
||
embed_struct->objTag.height = hyperSize.height;
|
||
|
||
//
|
||
// Remember an offset for the view to
|
||
// compensate for layout's default margins.
|
||
//
|
||
const short kLeftMargin = 8; // <20><><EFBFBD> These should be defined in mhyper.h!!!
|
||
const short kTopMargin = 8;
|
||
fHorizontalOffset = -kLeftMargin;
|
||
fVerticalOffset = -kTopMargin;
|
||
}
|
||
else
|
||
{
|
||
fHorizontalOffset = 0;
|
||
fVerticalOffset = 0;
|
||
}
|
||
|
||
ResizeImageTo(embed_struct->objTag.width, embed_struct->objTag.height, false);
|
||
ResizeFrameTo(embed_struct->objTag.width, embed_struct->objTag.height, false);
|
||
|
||
//
|
||
// NOTE: The position set here is not really valid because the x and y in
|
||
// embed_struct are not valid yet (we have to wait until DisplayEmbed
|
||
// (see below) is called the first time to get the real location).
|
||
// We go ahead and position ourselves anyway just so we have a superview
|
||
// and location initially.
|
||
//
|
||
Int32 x = embed_struct->objTag.x + embed_struct->objTag.x_offset + fHorizontalOffset;
|
||
Int32 y = embed_struct->objTag.y + embed_struct->objTag.y_offset + fVerticalOffset;
|
||
PlaceInSuperImageAt(x, y, false);
|
||
|
||
//
|
||
// Set up the NPWindow and NPPort for the first time. No one should
|
||
// have called NPL_EmbedSize before this point, or bogus values will
|
||
// get passed to the plugin!
|
||
//
|
||
ResetDrawRect();
|
||
}
|
||
|
||
|
||
void CPluginView::EmbedDisplay(LO_EmbedStruct* embed_struct, Boolean isPrinting)
|
||
{
|
||
fWindowed = (Boolean)NPL_IsEmbedWindowed(fApp);
|
||
fIsPrinting = isPrinting;
|
||
|
||
//
|
||
// If we<77>re not positioned yet, place our instance at the
|
||
// location specified by layout and make our view visible.
|
||
//
|
||
if (fPositioned == false)
|
||
{
|
||
Int32 x = embed_struct->objTag.x + embed_struct->objTag.x_offset + fHorizontalOffset;
|
||
Int32 y = embed_struct->objTag.y + embed_struct->objTag.y_offset + fVerticalOffset;
|
||
PlaceInSuperImageAt(x, y, false);
|
||
if (fWindowed)
|
||
Show();
|
||
else if (!fBrokenPlugin) {
|
||
fHidden = true;
|
||
Hide();
|
||
}
|
||
StartIdling();
|
||
fPositioned = true;
|
||
|
||
XP_ASSERT(fApp);
|
||
if (fApp != NULL)
|
||
NPL_EmbedSize(fApp); // Tell the plugin about its dimensions and location
|
||
|
||
Refresh();
|
||
}
|
||
|
||
// If this is a windowed plug-in, this call indicates that we've moved or our visibility
|
||
// changed.
|
||
if (fWindowed || fBrokenPlugin)
|
||
{
|
||
Rect frameRect;
|
||
SPoint32 imagePoint;
|
||
Int32 x, y;
|
||
|
||
if (IsVisible() && (embed_struct->objTag.ele_attrmask & LO_ELE_INVISIBLE))
|
||
Hide();
|
||
|
||
CalcPortFrameRect(frameRect);
|
||
GetSuperView()->PortToLocalPoint(topLeft(frameRect));
|
||
GetSuperView()->LocalToImagePoint(topLeft(frameRect), imagePoint);
|
||
|
||
x = embed_struct->objTag.x + embed_struct->objTag.x_offset + fHorizontalOffset;
|
||
y = embed_struct->objTag.y + embed_struct->objTag.y_offset + fVerticalOffset;
|
||
if ((imagePoint.h != x) || (imagePoint.v != y))
|
||
PlaceInSuperImageAt(x, y, true);
|
||
|
||
if (!IsVisible() && !(embed_struct->objTag.ele_attrmask & LO_ELE_INVISIBLE))
|
||
Show();
|
||
}
|
||
// For a windowless plug-in, this is where the plug-in actually draws.
|
||
else
|
||
{
|
||
EventRecord updateEvent;
|
||
//
|
||
// Always reset the drawing info before calling the plugin to draw.
|
||
//
|
||
ResetDrawRect();
|
||
|
||
::OSEventAvail(0, &updateEvent);
|
||
updateEvent.what = updateEvt;
|
||
(void) PassEvent(updateEvent);
|
||
}
|
||
}
|
||
|
||
|
||
void CPluginView::EmbedCreate(MWContext* context, LO_EmbedStruct* embed_struct)
|
||
{
|
||
fEmbedStruct = embed_struct;
|
||
fApp = (NPEmbeddedApp*) embed_struct->objTag.FE_Data;
|
||
Boolean printing = (context->type == MWContextPrint);
|
||
|
||
//
|
||
// Set the references between the view, the app, and the layout
|
||
// structure. Also set the pointer to the new instance<63>s
|
||
// window data (NPWindow), which is stored as part of our object
|
||
// (unless we are printing, in which case it already has a NPWindow).
|
||
// Then start up the stream for the plug-in (if applicable).
|
||
// If NPL_EmbedStart fails, it will delete the NPEmbeddedApp and
|
||
// associated XP data structures, so be sure to remove the
|
||
// embed_struct's reference to it.
|
||
//
|
||
if (fApp != NULL)
|
||
{
|
||
if (printing)
|
||
fOriginalView = (CPluginView*) fApp->fe_data;
|
||
fApp->fe_data = this;
|
||
embed_struct->objTag.FE_Data = fApp;
|
||
if (!printing)
|
||
fApp->wdata = GetNPWindow();
|
||
NPError err = NPL_EmbedStart(context, embed_struct, fApp);
|
||
if (err != NPERR_NO_ERROR)
|
||
fApp = NULL;
|
||
}
|
||
|
||
//
|
||
// Something went wrong? If we have no app, then layout can never
|
||
// tell us to delete the view (since the app is in the FE_Data of
|
||
// the layout structure), so we need to delete it here.
|
||
//
|
||
if (fApp == NULL)
|
||
{
|
||
delete this;
|
||
embed_struct->objTag.FE_Data = NULL;
|
||
}
|
||
}
|
||
|
||
|
||
void CPluginView::EmbedFree(MWContext* context, LO_EmbedStruct* embed_struct)
|
||
{
|
||
//
|
||
// Set our reference to the NPEmbeddedApp to NULL now, before
|
||
// calling NPL_EmbedDelete. NPL_EmbedDelete may re-call FE code
|
||
// after deleting the NPEmbeddedApp and we don<6F>t want to have
|
||
// a reference to a deleted app!
|
||
//
|
||
// XXX This is no longer necessary, as this is called in _response_
|
||
// to NPL_EmbedDelete.
|
||
NPEmbeddedApp* app = fApp;
|
||
fApp = NULL;
|
||
|
||
//
|
||
// If our original view field was set above in EmbedCreate, the
|
||
// the NPEmbeddedApp associated with this view was associated
|
||
// only temporarily for printing, so we should switch its
|
||
// references to its view and window back to their original values.
|
||
// If there is no original view, then we must be the original
|
||
// creator of the NPEmbeddedApp, so we should delete it.
|
||
//
|
||
if (fOriginalView != NULL)
|
||
{
|
||
app->fe_data = fOriginalView;
|
||
XP_ASSERT(app->wdata == fOriginalView->GetNPWindow());
|
||
app->wdata = fOriginalView->GetNPWindow();
|
||
}
|
||
|
||
ThrowIfNil_(context);
|
||
}
|
||
|
||
|
||
|
||
// <20><> event processing
|
||
|
||
void CPluginView::ClickSelf(const SMouseDownEvent& inMouseDown)
|
||
{
|
||
XP_ASSERT(fWindowed);
|
||
LView::ClickSelf(inMouseDown);
|
||
|
||
if (!fBrokenPlugin)
|
||
{
|
||
EventRecord mouseEvent = inMouseDown.macEvent; // inMouseDown is const, but PassEvent isn<73>t
|
||
(void) PassEvent(mouseEvent);
|
||
LCommander::SwitchTarget(this); // Once clicked, we can get keystrokes
|
||
}
|
||
}
|
||
|
||
void CPluginView::EventMouseUp(const EventRecord& inMouseUp)
|
||
{
|
||
XP_ASSERT(fWindowed);
|
||
LView::EventMouseUp(inMouseUp);
|
||
|
||
EventRecord mouseEvent = inMouseUp; // inMouseUp is const, but PassEvent isn<73>t
|
||
(void) PassEvent(mouseEvent);
|
||
}
|
||
|
||
|
||
Boolean CPluginView::ObeyCommand(CommandT inCommand, void *ioParam)
|
||
{
|
||
if (IsPluginCommand(inCommand)) {
|
||
// assume this is a plugin menu item, since menusharing didn't handle it.
|
||
EventRecord menuEvent;
|
||
::OSEventAvail(0, &menuEvent);
|
||
menuEvent.what = nsPluginEventType_MenuCommandEvent;
|
||
menuEvent.message = -inCommand; // PowerPlant encodes a raw menu selection as the negation of the selection.
|
||
return PassEvent(menuEvent);
|
||
}
|
||
return LCommander::ObeyCommand(inCommand, ioParam);
|
||
}
|
||
|
||
Boolean CPluginView::HandleKeyPress(const EventRecord& inKeyEvent)
|
||
{
|
||
if (fWindowed) {
|
||
EventRecord keyEvent = inKeyEvent; // inKeyEvent is const, but PassEvent isn<73>t
|
||
return PassEvent(keyEvent);
|
||
}
|
||
|
||
return false;
|
||
}
|
||
|
||
Boolean CPluginView::FocusDraw(LPane *inSubPane)
|
||
{
|
||
Boolean revealed = LView::FocusDraw(inSubPane);
|
||
|
||
//
|
||
// Make sure that any exposed popdown view is clipped out before drawing occurs.
|
||
//
|
||
CBrowserWindow::ClipOutPopdown(this);
|
||
|
||
return revealed;
|
||
}
|
||
|
||
void CPluginView::DrawSelf()
|
||
{
|
||
XP_ASSERT(!fHidden);
|
||
|
||
if (fPositioned == false) // Bail if layout hasn<73>t positioned us yet
|
||
return;
|
||
|
||
if (fBrokenPlugin)
|
||
DrawBroken(false);
|
||
else
|
||
{
|
||
//
|
||
// Always reset the drawing info before calling the plugin to draw.
|
||
// Although the MoveBy and ResizeFrameBy methods ensure that the
|
||
// drawing info is updated if the plugin is scrolled or its window
|
||
// is resized, the clip still needs to be set up every time before
|
||
// drawing because the area to draw will be different.
|
||
//
|
||
ResetDrawRect();
|
||
|
||
|
||
if (fIsPrinting)
|
||
{
|
||
this->PrintEmbedded();
|
||
fIsPrinting = false;
|
||
}
|
||
else
|
||
{
|
||
EventRecord updateEvent;
|
||
::OSEventAvail(0, &updateEvent);
|
||
updateEvent.what = updateEvt;
|
||
(void) PassEvent(updateEvent);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
|
||
void CPluginView::SpendTime(const EventRecord& inMacEvent)
|
||
{
|
||
EventRecord macEvent = inMacEvent; // inMacEvent is const, but PassEvent isn<73>t
|
||
(void) PassEvent(macEvent);
|
||
|
||
//
|
||
// If we<77>re in SpendTime because of a non-null event, send a
|
||
// null event too. Some plug-ins (e.g. Shockwave) rely on null
|
||
// events for animation, so it doesn<73>t matter if we<77>re giving
|
||
// them lots of time with mouseMoved or other events -- if they
|
||
// don<6F>t get null events, they don<6F>t animate fast.
|
||
//
|
||
if (macEvent.what != nullEvent)
|
||
{
|
||
macEvent.what = nullEvent;
|
||
(void) PassEvent(macEvent);
|
||
}
|
||
}
|
||
|
||
|
||
void CPluginView::ActivateSelf()
|
||
{
|
||
EventRecord activateEvent;
|
||
::OSEventAvail(0, &activateEvent);
|
||
activateEvent.what = activateEvt;
|
||
activateEvent.modifiers = activeFlag;
|
||
(void) PassEvent(activateEvent);
|
||
}
|
||
|
||
|
||
void CPluginView::DeactivateSelf()
|
||
{
|
||
EventRecord activateEvent;
|
||
::OSEventAvail(0, &activateEvent);
|
||
activateEvent.what = activateEvt;
|
||
(void) PassEvent(activateEvent);
|
||
}
|
||
|
||
//
|
||
// These two methods are called when we are targeted or
|
||
// untargeted. Since plugins want to know when they have
|
||
// the key focus, we create a new event type to pass to
|
||
// them.
|
||
//
|
||
|
||
void CPluginView::BeTarget()
|
||
{
|
||
XP_ASSERT(!fHidden);
|
||
CPluginView::sPluginTarget = this; // Parallel to LCommander::sTarget, except only for plug-ins
|
||
EventRecord focusEvent;
|
||
::OSEventAvail(0, &focusEvent);
|
||
focusEvent.what = nsPluginEventType_GetFocusEvent;
|
||
Boolean handled = PassEvent(focusEvent);
|
||
if (!handled) // If the plugin doesn<73>t want the focus,
|
||
SwitchTarget(GetSuperCommander()); // switch the focus back to our super
|
||
}
|
||
|
||
void CPluginView::DontBeTarget()
|
||
{
|
||
CPluginView::sPluginTarget = NULL; // Parallel to LCommander::sTarget, except only for plug-ins
|
||
EventRecord focusEvent;
|
||
::OSEventAvail(0, &focusEvent);
|
||
focusEvent.what = nsPluginEventType_LoseFocusEvent;
|
||
(void) PassEvent(focusEvent);
|
||
}
|
||
|
||
|
||
void CPluginView::AdjustCursorSelf(Point inPortPt, const EventRecord& inMacEvent)
|
||
{
|
||
XP_ASSERT(!fHidden);
|
||
EventRecord cursorEvent = inMacEvent;
|
||
cursorEvent.what = nsPluginEventType_AdjustCursorEvent;
|
||
|
||
Boolean handled = PassEvent(cursorEvent);
|
||
if (!handled)
|
||
LPane::AdjustCursorSelf(inPortPt, inMacEvent);
|
||
}
|
||
|
||
|
||
|
||
// <20><> positioning
|
||
|
||
void CPluginView::AdaptToSuperFrameSize(Int32 inSurrWidthDelta, Int32 inSurrHeightDelta, Boolean inRefresh)
|
||
{
|
||
LView::AdaptToSuperFrameSize(inSurrWidthDelta, inSurrHeightDelta, inRefresh);
|
||
|
||
//
|
||
// Our superview has changed size, so we could have changed size
|
||
// (if we<77>re bound to the superview) or changed clip (if we now
|
||
// overlap the edges of the superview).
|
||
//
|
||
if (fWindowed)
|
||
ResetDrawRect();
|
||
|
||
//
|
||
// If we are bound to our superview, we will change size as it
|
||
// changes size. Since the superview (the hyperview) is in turn
|
||
// bound to the window, we should adjust our NPWindow structure
|
||
// (done above in ResetDrawRect) and tell the plugin about the
|
||
// change (by calling NPL_EmbedSize). -bing 11/15/95
|
||
//
|
||
if (fApp != NULL)
|
||
{
|
||
SBooleanRect frameBinding;
|
||
GetFrameBinding(frameBinding);
|
||
if (frameBinding.top && frameBinding.bottom && frameBinding.left && frameBinding.right)
|
||
NPL_EmbedSize(fApp);
|
||
}
|
||
}
|
||
|
||
void CPluginView::MoveBy(Int32 inHorizDelta, Int32 inVertDelta, Boolean inRefresh)
|
||
{
|
||
LView::MoveBy(inHorizDelta, inVertDelta, inRefresh);
|
||
if (fWindowed)
|
||
ResetDrawRect();
|
||
}
|
||
|
||
|
||
|
||
// <20><><EFBFBD>dragging
|
||
|
||
void CPluginView::AdaptToNewSurroundings()
|
||
{
|
||
LView::AdaptToNewSurroundings();
|
||
|
||
//
|
||
// Set the port for dragging here, since we need
|
||
// a superview to get the port, and we don't have
|
||
// a superview until this method is called.
|
||
//
|
||
LDropArea::RemoveDropArea((LDropArea*)this, mDragWindow);
|
||
mDragWindow = GetMacPort();
|
||
LDropArea::AddDropArea((LDropArea*)this, mDragWindow);
|
||
}
|
||
|
||
Boolean CPluginView::DragIsAcceptable(DragReference /*inDragRef*/)
|
||
{
|
||
//
|
||
// We claim to accept drops, so we won't get the
|
||
// Navigator drag&drop behavior over the plug-in.
|
||
// If the plug-in installs its own drag handlers,
|
||
// it will get control after we're called and can
|
||
// handle the drag as it sees fit.
|
||
//
|
||
return true;
|
||
}
|
||
|
||
void CPluginView::HiliteDropArea(DragReference /*inDragRef*/)
|
||
{
|
||
// Don<6F>t hilite: let the plug-in do it if it accepts drags.
|
||
}
|
||
|
||
void CPluginView::UnhiliteDropArea(DragReference /*inDragRef*/)
|
||
{
|
||
// Don<6F>t unhilite: let the plug-in do it if it accepts drags.
|
||
}
|
||
|
||
|
||
|
||
|
||
// <20><><EFBFBD>events
|
||
|
||
// Passes the event to our plugin
|
||
Boolean CPluginView::PassEvent(EventRecord& inEvent)
|
||
{
|
||
if (fApp)
|
||
return NPL_HandleEvent(fApp, (NPEvent*)&inEvent, NULL);
|
||
else
|
||
return false;
|
||
}
|
||
|
||
|
||
void CPluginView::ResetDrawRect()
|
||
{
|
||
fNPWindow.window = &fNPPort;
|
||
|
||
if (fWindowed) {
|
||
|
||
fNPPort.port = (CGrafPtr) GetMacPort();
|
||
fNPWindow.x = mImageLocation.h;
|
||
fNPWindow.y = mImageLocation.v;
|
||
fNPWindow.width = mFrameSize.width;
|
||
fNPWindow.height = mFrameSize.height;
|
||
|
||
if (mRevealedRect.left < mRevealedRect.right) // Code from FocusDraw
|
||
{ // We are visible
|
||
XP_ASSERT(!fHidden);
|
||
fNPPort.portx = mPortOrigin.h;
|
||
fNPPort.porty = mPortOrigin.v;
|
||
|
||
fNPWindow.clipRect.top = mRevealedRect.top;
|
||
fNPWindow.clipRect.left = mRevealedRect.left;
|
||
fNPWindow.clipRect.right = mRevealedRect.right;
|
||
fNPWindow.clipRect.bottom = mRevealedRect.bottom;
|
||
}
|
||
else // We are invisible
|
||
{
|
||
fNPWindow.clipRect.top = 0;
|
||
fNPWindow.clipRect.left = 0;
|
||
fNPWindow.clipRect.right = 0;
|
||
fNPWindow.clipRect.bottom = 0;
|
||
}
|
||
}
|
||
else {
|
||
Rect frame;
|
||
Point localPoint, portPoint;
|
||
SPoint32 imagePoint;
|
||
Rect clipRect;
|
||
Point portOrigin;
|
||
|
||
// XXX This is gross. We're getting our parent and casting it down to a
|
||
// CHTMLView so that we can get element position and port information from it.
|
||
CHTMLView *parentView = (CHTMLView *)GetSuperView();
|
||
|
||
// Get the parent's port and port origin. Note that this will be different
|
||
// depending on whether it's onscreen or offscreen.
|
||
fNPPort.port = (CGrafPtr) parentView->GetCurrentPort(portOrigin);
|
||
|
||
// Get the local position from the hyperview. This is a function of the
|
||
// location of the layout element, the scrolled position and the position
|
||
// of the layer containing the embed.
|
||
parentView->CalcElementPosition((LO_Element *)fEmbedStruct, frame);
|
||
|
||
// Convert it into image coordinates
|
||
localPoint.h = frame.left - (fEmbedStruct->objTag.x + fEmbedStruct->objTag.x_offset);
|
||
localPoint.v = frame.top - (fEmbedStruct->objTag.y + fEmbedStruct->objTag.y_offset);
|
||
portPoint = localPoint;
|
||
localPoint.h -= portOrigin.h;
|
||
localPoint.v -= portOrigin.v;
|
||
parentView->LocalToImagePoint(localPoint, imagePoint);
|
||
|
||
fNPWindow.x = imagePoint.h;
|
||
fNPWindow.y = imagePoint.v;
|
||
fNPWindow.width = frame.right - frame.left;
|
||
fNPWindow.height = frame.bottom - frame.top;
|
||
|
||
fNPPort.portx = -localPoint.h;
|
||
fNPPort.porty = -localPoint.v;
|
||
|
||
// The clipRect in this case is the bounding box of the clip region
|
||
// set by the compositor. Convert to port coordinates.
|
||
clipRect = (*fNPPort.port->clipRgn)->rgnBBox;
|
||
topLeft(clipRect).h -= portOrigin.h;
|
||
topLeft(clipRect).v -= portOrigin.v;
|
||
botRight(clipRect).h -= portOrigin.h;
|
||
botRight(clipRect).v -= portOrigin.v;
|
||
|
||
fNPWindow.clipRect.top = clipRect.top;
|
||
fNPWindow.clipRect.left = clipRect.left;
|
||
fNPWindow.clipRect.right = clipRect.right;
|
||
fNPWindow.clipRect.bottom = clipRect.bottom;
|
||
|
||
// Keep the view's position in sync with that specified by layout
|
||
parentView->LocalToPortPoint(portPoint);
|
||
if ((portPoint.h != -mPortOrigin.h) || (portPoint.v != -mPortOrigin.v)) {
|
||
MoveBy(mPortOrigin.h + portPoint.h, mPortOrigin.v + portPoint.v, false);
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
//
|
||
// This method is used for printing fullscreen plugins, which might
|
||
// want the opportunity to completely take over printing the page.
|
||
// We will pass them whether the user clicked on the print button
|
||
// or the Print menu (<28>printOne<6E>), a handle to the print record,
|
||
// and a boolean that they can set to true if they actually want to
|
||
// handle the print. We return this boolean to our caller (CHyperView:
|
||
// ObeyCommand) so they know whether they should print or not.
|
||
// If plugins do not implement the Print entry point at all, the
|
||
// boolean <20>pluginPrinted<65> will still be at its default value (false),
|
||
// so we will still print.
|
||
//
|
||
Boolean CPluginView::PrintFullScreen(Boolean printOne, THPrint printRecHandle)
|
||
{
|
||
if (fApp == NULL)
|
||
return false;
|
||
|
||
NPPrint npPrint;
|
||
npPrint.mode = NP_FULL;
|
||
npPrint.print.fullPrint.pluginPrinted = false;
|
||
npPrint.print.fullPrint.printOne = printOne;
|
||
npPrint.print.fullPrint.platformPrint = (void*) printRecHandle;
|
||
|
||
NPL_Print(fApp, (void*) &npPrint);
|
||
|
||
return npPrint.print.fullPrint.pluginPrinted;
|
||
}
|
||
|
||
void CPluginView::PrintEmbedded()
|
||
{
|
||
if (fApp == NULL)
|
||
return;
|
||
|
||
NPPrint npPrint;
|
||
npPrint.mode = NP_EMBED;
|
||
npPrint.print.embedPrint.window = fNPWindow;
|
||
npPrint.print.embedPrint.platformPrint = (void*) fNPWindow.window; // Pass the NP_Port
|
||
|
||
NPL_Print(fApp, (void*) &npPrint);
|
||
}
|
||
|
||
|
||
|
||
|
||
void CPluginView::SetBrokenPlugin()
|
||
{
|
||
fBrokenPlugin = true;
|
||
fBrokenIcon = CIconList::GetIcon(326); // <20><><EFBFBD> Need a constant
|
||
// Tell layout that we're windowed so we can display an icon
|
||
LO_SetEmbedType(fEmbedStruct, PR_TRUE);
|
||
Refresh(); // Plugin will draw broken icon now that fBrokenPlugin is set
|
||
}
|
||
|
||
|
||
void CPluginView::DrawBroken(Boolean hilite)
|
||
{
|
||
//
|
||
// If the plugin is broken, we don<6F>t have a valid plugin instance
|
||
// to ask to draw, so we should handle drawing ourselves.
|
||
// Current behavior is to draw a box with a broken plugin icon
|
||
// in it.
|
||
//
|
||
Rect drawRect;
|
||
if (this->CalcLocalFrameRect(drawRect)) // We want a local rect since SetOrigin has been called
|
||
{
|
||
short height = drawRect.bottom - drawRect.top;
|
||
short width = drawRect.right - drawRect.left;
|
||
|
||
if (height >= 4 && width >= 4)
|
||
{
|
||
UGraphics::SetFore(CPrefs::Anchor);
|
||
FrameRect(&drawRect);
|
||
|
||
if (height >= 32 && width >= 32 && fBrokenIcon != NULL)
|
||
{
|
||
short centerX = (drawRect.right - drawRect.left) >> 1;
|
||
short centerY = (drawRect.bottom - drawRect.top) >> 1;
|
||
drawRect.top = centerY - 16;
|
||
drawRect.bottom = centerY + 16;
|
||
drawRect.left = centerX - 16;
|
||
drawRect.right = centerX + 16;
|
||
|
||
::PlotCIconHandle(&drawRect, atAbsoluteCenter, hilite ? ttSelected : ttNone, fBrokenIcon);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
|
||
#ifdef LAYERS
|
||
Boolean CPluginView::HandleEmbedEvent(CL_Event *event)
|
||
{
|
||
fe_EventStruct *fe_event = (fe_EventStruct *)event->fe_event;
|
||
|
||
EventRecord macEvent;
|
||
::OSEventAvail(0, &macEvent);
|
||
|
||
// For windowless plugins, the last draw might have been to the offscreen port,
|
||
// but for event handling, we want the current port to be the onscreen port (so
|
||
// that mouse coordinate conversion and the like can happen correctly).
|
||
if (!fWindowed)
|
||
FocusDraw();
|
||
|
||
switch (event->type) {
|
||
case CL_EVENT_MOUSE_BUTTON_DOWN:
|
||
{
|
||
//SMouseDownEvent *mouseDown = (SMouseDownEvent *)fe_event->event;
|
||
|
||
// Now pass the mouse event
|
||
//macEvent = mouseDown->macEvent;
|
||
// modified for new fe_EventStruct 1997-02-22 mjc
|
||
SMouseDownEvent mouseDown = fe_event->event.mouseDownEvent;
|
||
macEvent = mouseDown.macEvent;
|
||
}
|
||
break;
|
||
case CL_EVENT_MOUSE_BUTTON_UP:
|
||
case CL_EVENT_KEY_DOWN:
|
||
//macEvent = *(EventRecord *)fe_event->event;
|
||
macEvent = fe_event->event.macEvent; // 1997-02-22 mjc
|
||
break;
|
||
case CL_EVENT_MOUSE_MOVE:
|
||
//macEvent = *(EventRecord *)fe_event->event;
|
||
macEvent = fe_event->event.macEvent; // 1997-02-22 mjc
|
||
macEvent.what = nsPluginEventType_AdjustCursorEvent;
|
||
break;
|
||
case CL_EVENT_KEY_FOCUS_GAINED:
|
||
macEvent.what = nsPluginEventType_GetFocusEvent;
|
||
break;
|
||
case CL_EVENT_KEY_FOCUS_LOST:
|
||
macEvent.what = nsPluginEventType_LoseFocusEvent;
|
||
break;
|
||
default:
|
||
return false;
|
||
}
|
||
|
||
return PassEvent(macEvent);
|
||
}
|
||
#endif // LAYERS
|