Commit cde42748 authored by whitlocb's avatar whitlocb

Added optional callback data to CLI callback functions


git-svn-id: http://visit.ilight.com/svn/visit/trunk/src@3164 18c085ea-50e0-402c-830e-de6fd14e8384
parent 67591764
......@@ -119,12 +119,20 @@ default_handler_##Obj(Subject *subj, void *data) \
CallbackManager::CallbackHandlerData *cbData = (CallbackManager::CallbackHandlerData *)data; \
if(cbData->pycb != 0) \
{ \
PyObject *tuple = PyTuple_New(1);\
PyObject *tuple = PyTuple_New((cbData->pycb_data != 0) ? 2 : 1);\
PyObject *state = PyWrap((const T *)cbData->data); \
PyTuple_SET_ITEM(tuple, 0, state); \
if(cbData->pycb_data != 0) \
{\
Py_INCREF(cbData->pycb_data); \
PyTuple_SET_ITEM(tuple, 0, state); \
PyTuple_SET_ITEM(tuple, 1, cbData->pycb_data); \
}\
else\
PyTuple_SET_ITEM(tuple, 0, state); \
PyObject *ret = PyObject_Call(cbData->pycb, tuple, NULL); \
Py_DECREF(tuple); \
Py_DECREF(ret); \
if(ret != 0) \
Py_DECREF(ret); \
} \
}
SUPPORTED_STATE_OBJECTS
......@@ -283,7 +291,9 @@ GetOperatorConstructorFunction(AttributeSubject *subj)
// Creation: Tue Feb 5 11:20:33 PST 2008
//
// Modifications:
//
// Brad Whitlock, Wed Feb 6 10:39:09 PST 2008
// Added support for callback data.
//
// ****************************************************************************
//
......@@ -334,13 +344,26 @@ plugin_state_callback_handler(Subject *s, void *data)
// Now that we've wrapped the state object, call the user's
// Python callback function.
tuple = PyTuple_New(1);
PyTuple_SET_ITEM(tuple, 0, state);
if(cbData->pycb_data != 0)
{
tuple = PyTuple_New(2);
Py_INCREF(cbData->pycb_data);
PyTuple_SET_ITEM(tuple, 0, state);
PyTuple_SET_ITEM(tuple, 1, cbData->pycb_data);
}
else
{
tuple = PyTuple_New(1);
PyTuple_SET_ITEM(tuple, 0, state);
}
PyObject *ret = PyObject_Call(cbData->pycb, tuple, NULL);
// Restore the old state object
s->data = oldState;
// Delete the tuple (includes state)
// Delete the tuple (includes state, callback data ref)
Py_DECREF(tuple);
// Delete the return value
if(ret != 0)
Py_DECREF(ret);
}
}
......@@ -360,7 +383,9 @@ plugin_state_callback_handler(Subject *s, void *data)
// Creation: Mon Feb 4 09:48:11 PST 2008
//
// Modifications:
//
// Brad Whitlock, Wed Feb 6 10:50:11 PST 2008
// Added support for callback data.
//
// ****************************************************************************
static void
......@@ -370,12 +395,40 @@ ViewerRPC_callback(Subject *subj, void *data)
// If we have a handler for the particular ViewerRPC then call it.
ViewerRPC *rpc = (ViewerRPC *)cbData->data;
ViewerRPCCallbacks *rpcCB = (ViewerRPCCallbacks *)cbData->userdata;
PyObject *pycb = rpcCB->GetCallback(rpc->GetRPCType());
PyObject *pycb = rpcCB->GetCallback(rpc->GetRPCType());
PyObject *pycb_data = rpcCB->GetCallbackData(rpc->GetRPCType());
if(pycb != 0)
{
// Get the arguments for the rpc so we can pass them to the user's callback.
PyObject *args = args_ViewerRPC(rpc);
// If there's callback data, enlarge the tuple.
if(pycb_data != 0)
{
if(args == Py_None)
{
// Convert none to tuple containing callback data.
Py_DECREF(args);
args = PyTuple_New(1);
Py_INCREF(pycb_data);
PyTuple_SET_ITEM(args, 0, pycb_data);
}
else if(PyTuple_Check(args))
{
// Enlarge the tuple so we can append the callback data to it
PyObject *tuple = PyTuple_New(PyTuple_Size(args) + 1);
for(int i = 0; i < PyTuple_Size(args); ++i)
{
Py_INCREF(PyTuple_GET_ITEM(args, i));
PyTuple_SET_ITEM(tuple, i, PyTuple_GET_ITEM(args, i));
}
Py_INCREF(pycb_data);
PyTuple_SET_ITEM(tuple, PyTuple_Size(args), pycb_data);
Py_DECREF(args);
args = tuple;
}
}
// Call the user's callback function.
PyObject *ret = PyObject_Call(pycb, args, NULL);
......@@ -383,7 +436,8 @@ ViewerRPC_callback(Subject *subj, void *data)
Py_DECREF(args);
// Delete the return value.
Py_DECREF(ret);
if(ret != 0)
Py_DECREF(ret);
}
}
......
......@@ -145,7 +145,9 @@ CallbackManager::CallbackManager() : SimpleObserver(),
// Creation: Tue Feb 5 11:51:40 PST 2008
//
// Modifications:
//
// Brad Whitlock, Wed Feb 6 10:28:58 PST 2008
// Added support for callback data.
//
// ****************************************************************************
CallbackManager::~CallbackManager()
......@@ -157,6 +159,8 @@ CallbackManager::~CallbackManager()
it->first->Detach(this);
if(it->second.pycb != 0)
Py_DECREF(it->second.pycb);
if(it->second.pycb_data != 0)
Py_DECREF(it->second.pycb_data);
}
delete threading;
}
......@@ -198,7 +202,9 @@ CallbackManager::WorkAllowed()
// Creation: Tue Feb 5 11:52:45 PST 2008
//
// Modifications:
//
// Brad Whitlock, Wed Feb 6 10:29:21 PST 2008
// Added support for callback data.
//
// ****************************************************************************
void
......@@ -211,6 +217,8 @@ CallbackManager::SubjectRemoved(Subject *subj)
subj->Detach(this);
if(it->second.pycb != 0)
Py_DECREF(it->second.pycb);
if(it->second.pycb_data != 0)
Py_DECREF(it->second.pycb_data);
callbacks.erase(it);
}
threading->MUTEX_UNLOCK();
......@@ -356,7 +364,9 @@ CallbackManager::StartWork()
// Creation: Tue Feb 5 11:58:43 PST 2008
//
// Modifications:
//
// Brad Whitlock, Wed Feb 6 10:30:04 PST 2008
// Added support for callback data.
//
// ****************************************************************************
void
......@@ -393,6 +403,7 @@ CallbackManager::Work()
{
CallbackHandlerData cbData;
cbData.pycb = cb.pycb;
cbData.pycb_data = cb.pycb_data;
cbData.data = w.data;
cbData.userdata = cb.handler_data;
(*cb.handler)(key, (void *)&cbData);
......@@ -437,7 +448,9 @@ CallbackManager::Work()
// Creation: Tue Feb 5 12:00:47 PST 2008
//
// Modifications:
//
// Brad Whitlock, Wed Feb 6 10:31:09 PST 2008
// Added support for callback data.
//
// ****************************************************************************
void
......@@ -458,6 +471,7 @@ CallbackManager::RegisterHandler(Subject *subj, const std::string &cbName,
entry.addwork = addwork;
entry.addwork_data = addwork_data;
entry.pycb = 0;
entry.pycb_data = 0;
callbacks[subj] = entry;
nameToSubject[cbName] = subj;
......@@ -486,11 +500,13 @@ CallbackManager::RegisterHandler(Subject *subj, const std::string &cbName,
// Creation: Tue Feb 5 12:05:37 PST 2008
//
// Modifications:
//
// Brad Whitlock, Wed Feb 6 10:31:27 PST 2008
// Added support for callback data.
//
// ****************************************************************************
bool
CallbackManager::RegisterCallback(Subject *subj, PyObject *pycb)
CallbackManager::RegisterCallback(Subject *subj, PyObject *pycb, PyObject *pycb_data)
{
bool retval = false;
threading->MUTEX_LOCK();
......@@ -498,17 +514,19 @@ CallbackManager::RegisterCallback(Subject *subj, PyObject *pycb)
SubjectCallbackDataMap::iterator it = callbacks.find(subj);
if(it != callbacks.end())
{
if(PyCallable_Check(pycb))
{
if(it->second.pycb != 0)
Py_DECREF(it->second.pycb);
if(it->second.pycb != 0)
Py_DECREF(it->second.pycb);
if(it->second.pycb_data != 0)
Py_DECREF(it->second.pycb_data);
if(pycb != 0)
Py_INCREF(pycb);
callbacks[subj].pycb = pycb;
retval = true;
}
else
cerr << "RegisterCallback called with uncallable object" << endl;
if(pycb_data != 0)
Py_INCREF(pycb_data);
callbacks[subj].pycb = pycb;
callbacks[subj].pycb_data = pycb_data;
retval = true;
}
else
cerr << "RegisterCallback called with invalid subject." << endl;
......@@ -536,17 +554,20 @@ CallbackManager::RegisterCallback(Subject *subj, PyObject *pycb)
// Creation: Tue Feb 5 12:05:37 PST 2008
//
// Modifications:
//
// Brad Whitlock, Wed Feb 6 10:32:46 PST 2008
// Added support for callback data.
//
// ****************************************************************************
bool
CallbackManager::RegisterCallback(const std::string &name, PyObject *pycb)
CallbackManager::RegisterCallback(const std::string &name, PyObject *pycb,
PyObject *pycb_data)
{
bool retval = false;
StringSubjectMap::iterator it = nameToSubject.find(name);
if(it != nameToSubject.end())
{
retval = RegisterCallback(it->second, pycb);
retval = RegisterCallback(it->second, pycb, pycb_data);
}
else
cerr << "Could not register callback " << name.c_str() << endl;
......
......@@ -68,7 +68,9 @@ typedef bool (AddWorkCallback)(Subject *, void *data);
// Creation: Fri Feb 1 16:18:28 PST 2008
//
// Modifications:
//
// Brad Whitlock, Wed Feb 6 10:27:51 PST 2008
// Added support for callback data.
//
// ****************************************************************************
class CallbackManager : public SimpleObserver
......@@ -81,6 +83,7 @@ class CallbackManager : public SimpleObserver
AddWorkCallback *addwork;
void *addwork_data;
PyObject *pycb;
PyObject *pycb_data;
};
struct WorkItem
......@@ -100,6 +103,7 @@ public:
{
// The Python object that will handle the callback
PyObject *pycb;
PyObject *pycb_data;
// An instance of the subject that has the actual object contents that
// we had at the time the callback was received.
AttributeSubject *data;
......@@ -115,14 +119,14 @@ public:
void RegisterHandler(Subject *, const std::string &,
ObserverCallback *handler, void *handler_data,
AddWorkCallback *addwork, void *addwork_data);
bool RegisterCallback(const std::string &, PyObject *);
bool RegisterCallback(const std::string &, PyObject *, PyObject *);
void GetCallbackNames(stringVector &names) const;
PyObject *GetCallback(Subject *) const;
void WorkAllowed();
void Work();
private:
bool RegisterCallback(Subject *, PyObject *);
bool RegisterCallback(Subject *, PyObject *, PyObject *);
void StartWork();
StringSubjectMap nameToSubject;
......
......@@ -1380,7 +1380,8 @@ args_ViewerRPC(ViewerRPC *rpc)
default:
// The ViewerRPC is not handled so just wrap the whole ViewerRPC and pass
// that to the user's callback.
args = ViewerRPC_wrap_ViewerRPC(rpc);
args = PyTuple_New(1);
PyTuple_SET_ITEM(args, 0, ViewerRPC_wrap_ViewerRPC(rpc));
}
return args;
......
......@@ -53,7 +53,10 @@
ViewerRPCCallbacks::ViewerRPCCallbacks()
{
for(int r = 0; r < (int)ViewerRPC::MaxRPC; ++r)
{
pycb[r] = 0;
pycb_data[r] = 0;
}
}
// ****************************************************************************
......@@ -75,6 +78,8 @@ ViewerRPCCallbacks::~ViewerRPCCallbacks()
{
if(pycb[r] != 0)
Py_DECREF(pycb[r]);
if(pycb_data[r] != 0)
Py_DECREF(pycb_data[r]);
}
}
......@@ -110,10 +115,11 @@ ViewerRPCCallbacks::GetCallbackNames(stringVector &names)
// Arguments:
// rpcName : The name of the ViewerRPC for which we're installing a callback.
// cb : The user-provided callback.
// cbdata : callback data.
//
// Returns: True on success; False on failure.
//
// Note:
// Note: Call with NULL cb, cbdata to unregister the callback.
//
// Programmer: Brad Whitlock
// Creation: Tue Feb 5 11:47:52 PST 2008
......@@ -123,7 +129,8 @@ ViewerRPCCallbacks::GetCallbackNames(stringVector &names)
// ****************************************************************************
bool
ViewerRPCCallbacks::RegisterCallback(const std::string &rpcName, PyObject *cb)
ViewerRPCCallbacks::RegisterCallback(const std::string &rpcName, PyObject *cb,
PyObject *cbdata)
{
bool retval = false;
ViewerRPC::ViewerRPCType r;
......@@ -131,8 +138,14 @@ ViewerRPCCallbacks::RegisterCallback(const std::string &rpcName, PyObject *cb)
{
if(pycb[r] != 0)
Py_DECREF(pycb[r]);
if(pycb_data[r] != 0)
Py_DECREF(pycb_data[r]);
pycb[r] = cb;
Py_INCREF(pycb[r]);
pycb_data[r] = cbdata;
if(pycb[r] != 0)
Py_INCREF(pycb[r]);
if(pycb_data[r] != 0)
Py_INCREF(pycb_data[r]);
retval = true;
}
return retval;
......@@ -163,3 +176,29 @@ ViewerRPCCallbacks::GetCallback(ViewerRPC::ViewerRPCType r)
{
return pycb[r];
}
// ****************************************************************************
// Method: ViewerRPCCallbacks::GetCallbackData
//
// Purpose:
// Returns the user-defined callback data for the specified rpc.
//
// Arguments:
// r : The rpc whose callback data we want to access.
//
// Returns:
//
// Note:
//
// Programmer: Brad Whitlock
// Creation: Wed Feb 6 10:26:44 PST 2008
//
// Modifications:
//
// ****************************************************************************
PyObject *
ViewerRPCCallbacks::GetCallbackData(ViewerRPC::ViewerRPCType r)
{
return pycb_data[r];
}
......@@ -52,7 +52,9 @@
// Creation: Mon Feb 4 09:21:44 PST 2008
//
// Modifications:
//
// Brad Whitlock, Wed Feb 6 10:26:09 PST 2008
// Added callback data.
//
// ****************************************************************************
class ViewerRPCCallbacks
......@@ -62,10 +64,12 @@ public:
~ViewerRPCCallbacks();
void GetCallbackNames(stringVector &names);
bool RegisterCallback(const std::string &, PyObject *);
bool RegisterCallback(const std::string &, PyObject *, PyObject *);
PyObject *GetCallback(ViewerRPC::ViewerRPCType);
PyObject *GetCallbackData(ViewerRPC::ViewerRPCType);
private:
PyObject *pycb[ViewerRPC::MaxRPC];
PyObject *pycb_data[ViewerRPC::MaxRPC];
};
#endif
......@@ -12218,7 +12218,10 @@ visit_GetCallbackArgumentCount(PyObject *, PyObject *args)
// Creation: Fri Feb 1 16:53:02 PST 2008
//
// Modifications:
//
// Brad Whitlock, Wed Feb 6 10:17:24 PST 2008
// Added optional callback data and made it possible to unregister a
// callback by passing just the name.
//
// ****************************************************************************
PyObject *
......@@ -12228,17 +12231,28 @@ visit_RegisterCallback(PyObject *, PyObject *args)
ENSURE_CALLBACK_MANAGER_EXISTS();
char *name = 0;
PyObject *callback = 0;
if (!PyArg_ParseTuple(args, "sO", &name, &callback))
return NULL;
if(callback == 0 || !PyCallable_Check(callback))
PyObject *callback = 0, *callback_data = 0;
if (!PyArg_ParseTuple(args, "sOO", &name, &callback, &callback_data))
{
if (PyArg_ParseTuple(args, "sO", &name, &callback))
callback_data = 0;
else
{
if(PyArg_ParseTuple(args, "s", &name))
callback = callback_data = 0;
else
return NULL;
}
PyErr_Clear();
}
if(callback != 0 && !PyCallable_Check(callback))
{
VisItErrorFunc("The object passed to RegisterCallback is not callable.");
return NULL;
}
// Try and register a ViewerRPC callback.
bool failed = !rpcCallbacks->RegisterCallback(name, callback);
bool failed = !rpcCallbacks->RegisterCallback(name, callback, callback_data);
// Try and register a state callback instead.
if(failed)
......@@ -12251,7 +12265,7 @@ visit_RegisterCallback(PyObject *, PyObject *args)
{
if(names[i] == name)
{
callbackMgr->RegisterCallback(name, callback);
callbackMgr->RegisterCallback(name, callback, callback_data);
failed = false;
break;
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment