%{ // //#define PYGDBG_ENABLED #ifdef PYGDBG_ENABLED #define PYGLOG(...) msg(__VA_ARGS__) #else #define PYGLOG(...) #endif //------------------------------------------------------------------------- class py_customidamemo_t; class lookup_info_t { public: struct entry_t { entry_t() : form(NULL), view(NULL), py_view(NULL) {} private: TForm *form; TCustomControl *view; py_customidamemo_t *py_view; friend class lookup_info_t; }; entry_t &new_entry(py_customidamemo_t *py_view) { QASSERT(30454, py_view != NULL && !find_by_py_view(NULL, NULL, py_view)); entry_t &e = entries.push_back(); e.py_view = py_view; return e; } void commit(entry_t &e, TForm *form, TCustomControl *view) { QASSERT(30455, &e >= entries.begin() && &e < entries.end()); QASSERT(30456, form != NULL && view != NULL && e.py_view != NULL && !find_by_form(NULL, NULL, form) && !find_by_view(NULL, NULL, view) && find_by_py_view(NULL, NULL, e.py_view)); e.form = form; e.view = view; } #define FIND_BY__BODY(crit, res1, res2) \ { \ for ( entries_t::const_iterator it = entries.begin(); it != entries.end(); ++it ) \ { \ const entry_t &e = *it; \ if ( e.crit == crit ) \ { \ if ( out_##res1 != NULL ) \ *out_##res1 = e.res1; \ if ( out_##res2 != NULL ) \ *out_##res2 = e.res2; \ return true; \ } \ } \ return false; \ } bool find_by_form(TCustomControl **out_view, py_customidamemo_t **out_py_view, const TForm *form) const FIND_BY__BODY(form, view, py_view); bool find_by_view(TForm **out_form, py_customidamemo_t **out_py_view, const TCustomControl *view) const FIND_BY__BODY(view, form, py_view); bool find_by_py_view(TForm **out_form, TCustomControl **out_view, const py_customidamemo_t *py_view) const FIND_BY__BODY(py_view, view, form); #undef FIND_BY__BODY bool del_by_py_view(const py_customidamemo_t *py_view) { for ( entries_t::iterator it = entries.begin(); it != entries.end(); ++it ) { if ( it->py_view == py_view ) { entries.erase(it); return true; } } return false; } private: typedef qvector entries_t; entries_t entries; }; //------------------------------------------------------------------------- template T *view_extract_this(PyObject *self) { PYW_GIL_CHECK_LOCKED_SCOPE(); ref_t py_this(PyW_TryGetAttrString(self, S_M_THIS)); if ( py_this == NULL || !PyCObject_Check(py_this.o) ) return NULL; return (T*) PyCObject_AsVoidPtr(py_this.o); } //------------------------------------------------------------------------- class py_customidamemo_t { void convert_node_info( node_info_t *out, uint32 *out_flags, ref_t py_nodeinfo) { if ( out_flags != NULL ) *out_flags = 0; #define COPY_PROP(checker, converter, pname, flag) \ do \ { \ newref_t pname(PyObject_GetAttrString(py_nodeinfo.o, #pname)); \ if ( pname != NULL && checker(pname.o) ) \ { \ out->pname = converter(pname.o); \ if ( out_flags != NULL ) \ *out_flags |= flag; \ } \ } while ( false ) #define COPY_ULONG_PROP(pname, flag) COPY_PROP(PyNumber_Check, PyLong_AsUnsignedLong, pname, flag) #define COPY_STRING_PROP(pname, flag) COPY_PROP(PyString_Check, PyString_AsString, pname, flag) COPY_ULONG_PROP(bg_color, NIF_BG_COLOR); COPY_ULONG_PROP(frame_color, NIF_FRAME_COLOR); COPY_ULONG_PROP(ea, NIF_EA); COPY_STRING_PROP(text, NIF_TEXT); #undef COPY_STRING_PROP #undef COPY_ULONG_PROP #undef COPY_PROP } enum { GRBASE_HAVE_VIEW_ACTIVATED = 0x001, GRBASE_HAVE_VIEW_DEACTIVATED = 0x002, GRBASE_HAVE_KEYDOWN = 0x004, GRBASE_HAVE_POPUP = 0x008, GRBASE_HAVE_VIEW_CLICK = 0x010, GRBASE_HAVE_VIEW_DBLCLICK = 0x020, GRBASE_HAVE_VIEW_CURPOS = 0x040, GRBASE_HAVE_CLOSE = 0x080, GRBASE_HAVE_VIEW_SWITCHED = 0x100, GRBASE_HAVE_VIEW_MOUSE_OVER = 0x200, GRBASE_HAVE_VIEW_MOUSE_MOVED = 0x400, }; static void ensure_view_callbacks_installed(); int cb_flags; // number of arguments for: int ovc_num_args; // OnViewClick implementation int ovdc_num_args; // OnViewDblclick implementation int ovmo_num_args; // OnViewMouseOver implementation int ovmm_num_args; // OnViewMouseMoved implementation protected: ref_t self; TCustomControl *view; // This is called after having modified the // node properties in the IDB. In case an // implementation is performing some caching, // this is a chance to update that cache. // If 'ni' is NULL, then the node info was deleted. virtual void node_info_modified( int /*n*/, const node_info_t * /*ni*/, uint32 /*flags*/) {} struct callback_id_t { qstring name; int have; }; struct callbacks_ids_t : public qvector { void add(const char *_n, int _h) { callback_id_t &o = push_back(); o.name = _n; o.have = _h; } }; callbacks_ids_t cbids; bool collect_pyobject_callbacks(PyObject *self); virtual void collect_class_callbacks_ids(callbacks_ids_t *out); void install_custom_viewer_handlers(); // Bi-directionally bind/unbind the Python object and this controller. bool bind(PyObject *_self, TCustomControl *view); void unbind(); static lookup_info_t lookup_info; friend TForm *pycim_get_tform(PyObject *self); friend TCustomControl *pycim_get_tcustom_control(PyObject *self); public: py_customidamemo_t(); virtual ~py_customidamemo_t(); virtual void refresh() { refresh_viewer(view); } void set_node_info(PyObject *py_node_idx, PyObject *py_node_info, PyObject *py_flags); void set_nodes_infos(PyObject *dict); PyObject *get_node_info(PyObject *py_node_idx); void del_nodes_infos(PyObject *py_nodes); PyObject *get_current_renderer_type(); void set_current_renderer_type(PyObject *py_rto); PyObject *create_groups(PyObject *groups_infos); PyObject *delete_groups(PyObject *groups, PyObject *new_current); PyObject *set_groups_visibility(PyObject *groups, PyObject *expand, PyObject *new_current); // View events void on_view_activated(); void on_view_deactivated(); void on_view_keydown(int key, int state); void on_view_popup(); void on_view_click(const view_mouse_event_t *event); void on_view_dblclick(const view_mouse_event_t *event); void on_view_curpos(); void on_view_close(); void on_view_switched(tcc_renderer_type_t rt); void on_view_mouse_over(const view_mouse_event_t *event); void on_view_mouse_moved(const view_mouse_event_t *event); inline bool has_callback(int flag) { return (cb_flags & flag) != 0; } int get_py_method_arg_count(char *method_name); // View events that are bound with 'set_custom_viewer_handler()'. static void idaapi s_on_view_mouse_moved( TCustomControl *cv, int shift, view_mouse_event_t *e, void *ud); }; //------------------------------------------------------------------------- py_customidamemo_t::py_customidamemo_t() : self(newref_t(NULL)), view(NULL) { PYGLOG("%p: py_customidamemo_t()\n", this); ensure_view_callbacks_installed(); ovc_num_args = -1; ovdc_num_args = -1; ovmo_num_args = -1; ovmm_num_args = -1; } //------------------------------------------------------------------------- py_customidamemo_t::~py_customidamemo_t() { PYGLOG("%p: ~py_customidamemo_t()\n", this); unbind(); lookup_info.del_by_py_view(this); } //------------------------------------------------------------------------- void py_customidamemo_t::ensure_view_callbacks_installed() { static bool installed = false; if ( !installed ) { struct ida_local lambda_t { static int idaapi callback(void * /*ud*/, int code, va_list va) { py_customidamemo_t *py_view; if ( lookup_info.find_by_view(NULL, &py_view, va_arg(va, TCustomControl *)) ) { PYW_GIL_GET; switch ( code ) { case view_activated: py_view->on_view_activated(); break; case view_deactivated: py_view->on_view_deactivated(); break; case view_keydown: { int key = va_arg(va, int); int state = va_arg(va, int); py_view->on_view_keydown(key, state); } break; case obsolete_view_popup: py_view->on_view_popup(); break; case view_click: case view_dblclick: { const view_mouse_event_t *event = va_arg(va, view_mouse_event_t*); if ( code == view_click ) py_view->on_view_click(event); else py_view->on_view_dblclick(event); } break; case view_curpos: py_view->on_view_curpos(); break; case view_close: py_view->on_view_close(); delete py_view; break; case view_switched: { tcc_renderer_type_t rt = (tcc_renderer_type_t) va_arg(va, int); py_view->on_view_switched(rt); } break; case view_mouse_over: { const view_mouse_event_t *event = va_arg(va, view_mouse_event_t*); py_view->on_view_mouse_over(event); } break; } } return 0; } }; hook_to_notification_point(HT_VIEW, lambda_t::callback, NULL); installed = true; } } //------------------------------------------------------------------------- void py_customidamemo_t::set_node_info( PyObject *py_node_idx, PyObject *py_node_info, PyObject *py_flags) { if ( !PyNumber_Check(py_node_idx) || !PyNumber_Check(py_flags) ) return; borref_t py_idx(py_node_idx); borref_t py_ni(py_node_info); borref_t py_fl(py_flags); node_info_t ni; convert_node_info(&ni, NULL, py_ni); int idx = PyInt_AsLong(py_idx.o); uint32 flgs = PyLong_AsLong(py_fl.o); viewer_set_node_info(view, idx, ni, flgs); node_info_modified(idx, &ni, flgs); } //------------------------------------------------------------------------- void py_customidamemo_t::set_nodes_infos(PyObject *dict) { if ( !PyDict_Check(dict) ) return; Py_ssize_t pos = 0; PyObject *o_key, *o_value; while ( PyDict_Next(dict, &pos, &o_key, &o_value) ) { borref_t key(o_key); borref_t value(o_value); if ( !PyNumber_Check(key.o) ) continue; uint32 flags; node_info_t ni; convert_node_info(&ni, &flags, value); int idx = PyInt_AsLong(key.o); viewer_set_node_info(view, idx, ni, flags); node_info_modified(idx, &ni, flags); } } //------------------------------------------------------------------------- PyObject *py_customidamemo_t::get_node_info(PyObject *py_node_idx) { if ( !PyNumber_Check(py_node_idx) ) Py_RETURN_NONE; node_info_t ni; if ( !viewer_get_node_info(view, &ni, PyInt_AsLong(py_node_idx)) ) Py_RETURN_NONE; return Py_BuildValue("(kkks)", ni.bg_color, ni.frame_color, ni.ea, ni.text.c_str()); } //------------------------------------------------------------------------- void py_customidamemo_t::del_nodes_infos(PyObject *py_nodes) { if ( !PySequence_Check(py_nodes) ) return; Py_ssize_t sz = PySequence_Size(py_nodes); for ( Py_ssize_t i = 0; i < sz; ++i ) { newref_t item(PySequence_GetItem(py_nodes, i)); if ( !PyNumber_Check(item.o) ) continue; int idx = PyInt_AsLong(item.o); viewer_del_node_info(view, idx); node_info_modified(idx, NULL, 0); } } //------------------------------------------------------------------------- PyObject *py_customidamemo_t::get_current_renderer_type() { tcc_renderer_type_t rt = get_view_renderer_type(view); return PyLong_FromLong(long(rt)); } //------------------------------------------------------------------------- void py_customidamemo_t::set_current_renderer_type(PyObject *py_rto) { tcc_renderer_type_t rt = TCCRT_INVALID; borref_t py_rt(py_rto); if ( PyNumber_Check(py_rt.o) ) { rt = tcc_renderer_type_t(PyLong_AsLong(py_rt.o)); set_view_renderer_type(view, rt); } } //------------------------------------------------------------------------- PyObject *py_customidamemo_t::create_groups(PyObject *_groups_infos) { if ( !PySequence_Check(_groups_infos) ) Py_RETURN_NONE; borref_t groups_infos(_groups_infos); groups_crinfos_t gis; Py_ssize_t sz = PySequence_Size(groups_infos.o); for ( Py_ssize_t i = 0; i < sz; ++i ) { newref_t item(PySequence_GetItem(groups_infos.o, i)); if ( !PyDict_Check(item.o) ) continue; borref_t nodes(PyDict_GetItemString(item.o, "nodes")); if ( nodes.o == NULL || !PySequence_Check(nodes.o) ) continue; borref_t text(PyDict_GetItemString(item.o, "text")); if ( text.o == NULL || !PyString_Check(text.o) ) continue; group_crinfo_t gi; Py_ssize_t nodes_cnt = PySequence_Size(nodes.o); for ( Py_ssize_t k = 0; k < nodes_cnt; ++k ) { newref_t node(PySequence_GetItem(nodes.o, k)); if ( PyInt_Check(node.o) ) gi.nodes.add_unique(PyInt_AsLong(node.o)); } if ( !gi.nodes.empty() ) { gi.text = PyString_AsString(text.o); gis.push_back(gi); } } intvec_t groups; if ( gis.empty() || !viewer_create_groups(view, &groups, gis) || groups.empty() ) Py_RETURN_NONE; PyObject *py_groups = PyList_New(0); for ( intvec_t::const_iterator it = groups.begin(); it != groups.end(); ++it ) PyList_Append(py_groups, PyInt_FromLong(long(*it))); return py_groups; } //------------------------------------------------------------------------- static void pynodes_to_idanodes(intvec_t *idanodes, ref_t pynodes) { Py_ssize_t sz = PySequence_Size(pynodes.o); for ( Py_ssize_t i = 0; i < sz; ++i ) { newref_t item(PySequence_GetItem(pynodes.o, i)); if ( !PyInt_Check(item.o) ) continue; idanodes->add_unique(PyInt_AsLong(item.o)); } } //------------------------------------------------------------------------- PyObject *py_customidamemo_t::delete_groups(PyObject *_groups, PyObject *_new_current) { if ( !PySequence_Check(_groups) || !PyNumber_Check(_new_current) ) Py_RETURN_NONE; borref_t groups(_groups); borref_t new_current(_new_current); intvec_t ida_groups; pynodes_to_idanodes(&ida_groups, groups); if ( ida_groups.empty() ) Py_RETURN_NONE; if ( viewer_delete_groups(view, ida_groups, int(PyInt_AsLong(new_current.o))) ) Py_RETURN_TRUE; else Py_RETURN_FALSE; } //------------------------------------------------------------------------- PyObject *py_customidamemo_t::set_groups_visibility(PyObject *_groups, PyObject *_expand, PyObject *_new_current) { if ( !PySequence_Check(_groups) || !PyBool_Check(_expand) || !PyNumber_Check(_new_current) ) Py_RETURN_NONE; borref_t groups(_groups); borref_t expand(_expand); borref_t new_current(_new_current); intvec_t ida_groups; pynodes_to_idanodes(&ida_groups, groups); if ( ida_groups.empty() ) Py_RETURN_NONE; if ( viewer_set_groups_visibility(view, ida_groups, expand.o == Py_True, int(PyInt_AsLong(new_current.o))) ) Py_RETURN_TRUE; else Py_RETURN_FALSE; } //------------------------------------------------------------------------- bool py_customidamemo_t::bind(PyObject *_self, TCustomControl *view) { if ( this->self != NULL || this->view != NULL ) return false; PYGLOG("%p: py_customidamemo_t::bind(_self=%p, view=%p)\n", this, _self, view); PYW_GIL_CHECK_LOCKED_SCOPE(); newref_t py_cobj(PyCObject_FromVoidPtr(this, NULL)); PyObject_SetAttrString(_self, S_M_THIS, py_cobj.o); this->self = borref_t(_self); this->view = view; return true; } //------------------------------------------------------------------------- void py_customidamemo_t::unbind() { if ( self == NULL ) return; PYGLOG("%p: py_customidamemo_t::unbind(); self.o=%p, view=%p\n", this, self.o, view); PYW_GIL_CHECK_LOCKED_SCOPE(); newref_t py_cobj(PyCObject_FromVoidPtr(NULL, NULL)); PyObject_SetAttrString(self.o, S_M_THIS, py_cobj.o); self = newref_t(NULL); view = NULL; } //------------------------------------------------------------------------- void idaapi py_customidamemo_t::s_on_view_mouse_moved( TCustomControl *cv, int shift, view_mouse_event_t *e, void *ud) { PYW_GIL_GET; py_customidamemo_t *_this = (py_customidamemo_t *) ud; _this->on_view_mouse_moved(e); } //------------------------------------------------------------------------- int py_customidamemo_t::get_py_method_arg_count(char *method_name) { newref_t method(PyObject_GetAttrString(self.o, method_name)); if ( method != NULL && PyCallable_Check(method.o) ) { newref_t fc(PyObject_GetAttrString(method.o, "func_code")); if ( fc != NULL ) { newref_t ac(PyObject_GetAttrString(fc.o, "co_argcount")); if ( ac != NULL ) return PyInt_AsLong(ac.o); } } return -1; } //------------------------------------------------------------------------- void py_customidamemo_t::collect_class_callbacks_ids(callbacks_ids_t *out) { out->add(S_ON_VIEW_ACTIVATED, GRBASE_HAVE_VIEW_ACTIVATED); out->add(S_ON_VIEW_DEACTIVATED, GRBASE_HAVE_VIEW_DEACTIVATED); out->add(S_ON_VIEW_KEYDOWN, GRBASE_HAVE_KEYDOWN); out->add(S_ON_POPUP, GRBASE_HAVE_POPUP); out->add(S_ON_VIEW_CLICK, GRBASE_HAVE_VIEW_CLICK); out->add(S_ON_VIEW_DBLCLICK, GRBASE_HAVE_VIEW_DBLCLICK); out->add(S_ON_VIEW_CURPOS, GRBASE_HAVE_VIEW_CURPOS); out->add(S_ON_CLOSE, GRBASE_HAVE_CLOSE); out->add(S_ON_VIEW_SWITCHED, GRBASE_HAVE_VIEW_SWITCHED); out->add(S_ON_VIEW_MOUSE_OVER, GRBASE_HAVE_VIEW_MOUSE_OVER); out->add(S_ON_VIEW_MOUSE_MOVED, GRBASE_HAVE_VIEW_MOUSE_MOVED); } //------------------------------------------------------------------------- bool py_customidamemo_t::collect_pyobject_callbacks(PyObject *o) { callbacks_ids_t cbids; collect_class_callbacks_ids(&cbids); cb_flags = 0; for ( callbacks_ids_t::const_iterator it = cbids.begin(); it != cbids.end(); ++it ) { const callback_id_t &cbid = *it; ref_t attr(PyW_TryGetAttrString(o, cbid.name.c_str())); int have = cbid.have; // Mandatory fields not present? if ( (attr == NULL && have <= 0 ) // Mandatory callback fields present but not callable? || (attr != NULL && have >= 0 && PyCallable_Check(attr.o) == 0)) { return false; } if ( have > 0 && attr != NULL ) cb_flags |= have; } return true; } //------------------------------------------------------------------------- void py_customidamemo_t::install_custom_viewer_handlers() { if ( has_callback(GRBASE_HAVE_VIEW_MOUSE_MOVED) ) { // Set user-data set_custom_viewer_handler(view, CVH_USERDATA, (void *)this); // set_custom_viewer_handler(view, CVH_MOUSEMOVE, (void *)s_on_view_mouse_moved); } } //------------------------------------------------------------------------- #define CHK_EVT(flag_needed) \ if ( self == NULL || !has_callback(flag_needed) ) \ return; \ PYW_GIL_CHECK_LOCKED_SCOPE() #ifdef PYGDBG_ENABLED #define CHK_RES() \ do \ { \ PYGLOG("%s: return code: %p\n", __FUNCTION__, result.o); \ if (PyErr_Occurred()) \ PyErr_Print(); \ } while ( false ) #else #define CHK_RES() \ do \ { \ if (PyErr_Occurred()) \ PyErr_Print(); \ } while ( false ) #endif //------------------------------------------------------------------------- void py_customidamemo_t::on_view_activated() { CHK_EVT(GRBASE_HAVE_VIEW_ACTIVATED); newref_t result( PyObject_CallMethod( self.o, (char *)S_ON_VIEW_ACTIVATED, NULL)); CHK_RES(); } //------------------------------------------------------------------------- void py_customidamemo_t::on_view_deactivated() { CHK_EVT(GRBASE_HAVE_VIEW_DEACTIVATED); newref_t result( PyObject_CallMethod( self.o, (char *)S_ON_VIEW_DEACTIVATED, NULL)); CHK_RES(); } //------------------------------------------------------------------------- void py_customidamemo_t::on_view_keydown(int key, int state) { CHK_EVT(GRBASE_HAVE_KEYDOWN); newref_t result( PyObject_CallMethod( self.o, (char *)S_ON_VIEW_KEYDOWN, "ii", key, state)); CHK_RES(); } //------------------------------------------------------------------------- void py_customidamemo_t::on_view_popup() { CHK_EVT(GRBASE_HAVE_POPUP); newref_t result( PyObject_CallMethod( self.o, (char *)S_ON_POPUP, NULL)); CHK_RES(); } //------------------------------------------------------------------------- static PyObject *build_renderer_pos_swig_proxy(const view_mouse_event_t *event) { return SWIG_NewPointerObj( SWIG_as_voidptr(&event->renderer_pos), SWIGTYPE_p_renderer_pos_info_t, 0); } //------------------------------------------------------------------------- void py_customidamemo_t::on_view_click(const view_mouse_event_t *event) { CHK_EVT(GRBASE_HAVE_VIEW_CLICK); if ( ovc_num_args < 0 ) ovc_num_args = get_py_method_arg_count((char*)S_ON_VIEW_CLICK); if ( ovc_num_args == 6 ) { PyObject *rpos = build_renderer_pos_swig_proxy(event); newref_t result( PyObject_CallMethod( self.o, (char *)S_ON_VIEW_CLICK, "iiiiO", event->x, event->y, event->state, event->button, rpos)); CHK_RES(); } else if ( ovc_num_args == 5 ) { newref_t result( PyObject_CallMethod( self.o, (char *)S_ON_VIEW_CLICK, "iiii", event->x, event->y, event->state, event->button)); CHK_RES(); } else { newref_t result( PyObject_CallMethod( self.o, (char *)S_ON_VIEW_CLICK, "iii", event->x, event->y, event->state)); CHK_RES(); } } //------------------------------------------------------------------------- void py_customidamemo_t::on_view_dblclick(const view_mouse_event_t *event) { CHK_EVT(GRBASE_HAVE_VIEW_DBLCLICK); if ( ovdc_num_args < 0 ) ovdc_num_args = get_py_method_arg_count((char*)S_ON_VIEW_DBLCLICK); if ( ovdc_num_args == 5 ) { PyObject *rpos = build_renderer_pos_swig_proxy(event); newref_t result( PyObject_CallMethod( self.o, (char *)S_ON_VIEW_DBLCLICK, "iiiO", event->x, event->y, event->state, rpos)); CHK_RES(); } else { newref_t result( PyObject_CallMethod( self.o, (char *)S_ON_VIEW_DBLCLICK, "iii", event->x, event->y, event->state)); CHK_RES(); } } //------------------------------------------------------------------------- void py_customidamemo_t::on_view_curpos() { CHK_EVT(GRBASE_HAVE_VIEW_CURPOS); newref_t result( PyObject_CallMethod( self.o, (char *)S_ON_VIEW_CURPOS, NULL)); CHK_RES(); } //------------------------------------------------------------------------- void py_customidamemo_t::on_view_close() { CHK_EVT(GRBASE_HAVE_CLOSE); newref_t result(PyObject_CallMethod(self.o, (char *)S_ON_CLOSE, NULL)); CHK_RES(); } //------------------------------------------------------------------------- void py_customidamemo_t::on_view_switched(tcc_renderer_type_t rt) { CHK_EVT(GRBASE_HAVE_VIEW_SWITCHED); newref_t result(PyObject_CallMethod(self.o, (char *)S_ON_VIEW_SWITCHED, "i", int(rt))); CHK_RES(); } //------------------------------------------------------------------------- static ref_t build_current_graph_item_tuple(int *out_icode, const view_mouse_event_t *event) { const selection_item_t *item = event->location.item; ref_t tuple; if ( (event->rtype == TCCRT_GRAPH || event->rtype == TCCRT_PROXIMITY) && item != NULL ) { if ( item->is_node ) { *out_icode = 1; tuple = newref_t(Py_BuildValue("(i)", item->node)); } else { *out_icode = 2; tuple = newref_t(Py_BuildValue("(ii)", item->elp.e.src, item->elp.e.dst)); } } else { *out_icode = 0; tuple = newref_t(Py_BuildValue("()")); } return tuple; } //------------------------------------------------------------------------- void py_customidamemo_t::on_view_mouse_over(const view_mouse_event_t *event) { CHK_EVT(GRBASE_HAVE_VIEW_MOUSE_OVER); if ( ovmo_num_args < 0 ) ovmo_num_args = get_py_method_arg_count((char*)S_ON_VIEW_MOUSE_OVER); if ( event->rtype != TCCRT_GRAPH && event->rtype != TCCRT_PROXIMITY ) return; int icode; ref_t tuple = build_current_graph_item_tuple(&icode, event); if ( ovmo_num_args == 7 ) { PyObject *rpos = build_renderer_pos_swig_proxy(event); newref_t result(PyObject_CallMethod( self.o, (char *)S_ON_VIEW_MOUSE_OVER, "iiiiOO", event->x, event->y, event->state, icode, tuple.o, rpos)); CHK_RES(); } else { newref_t result(PyObject_CallMethod( self.o, (char *)S_ON_VIEW_MOUSE_OVER, "iiiiO", event->x, event->y, event->state, icode, tuple.o)); CHK_RES(); } } //------------------------------------------------------------------------- void py_customidamemo_t::on_view_mouse_moved(const view_mouse_event_t *event) { CHK_EVT(GRBASE_HAVE_VIEW_MOUSE_MOVED); if ( ovmm_num_args < 0 ) ovmm_num_args = get_py_method_arg_count((char*)S_ON_VIEW_MOUSE_MOVED); int icode; ref_t tuple = build_current_graph_item_tuple(&icode, event); if ( ovmm_num_args == 7 ) { PyObject *rpos = build_renderer_pos_swig_proxy(event); newref_t result(PyObject_CallMethod( self.o, (char *)S_ON_VIEW_MOUSE_MOVED, "iiiiOO", event->x, event->y, event->state, icode, tuple.o, rpos)); CHK_RES(); } } #undef CHK_RES #undef CHK_EVT //------------------------------------------------------------------------- //------------------------------------------------------------------------- #define GET_THIS() py_customidamemo_t *_this = view_extract_this(self) #define CHK_THIS() \ GET_THIS(); \ if ( _this == NULL ) \ return #define CHK_THIS_OR_NULL() \ GET_THIS(); \ if ( _this == NULL ) \ return NULL; #define CHK_THIS_OR_NONE() \ GET_THIS(); \ if ( _this == NULL ) \ Py_RETURN_NONE //------------------------------------------------------------------------- void pygc_refresh(PyObject *self) { CHK_THIS(); _this->refresh(); } //------------------------------------------------------------------------- void pygc_set_node_info(PyObject *self, PyObject *py_node_idx, PyObject *py_node_info, PyObject *py_flags) { CHK_THIS(); _this->set_node_info(py_node_idx, py_node_info, py_flags); } //------------------------------------------------------------------------- void pygc_set_nodes_infos(PyObject *self, PyObject *values) { CHK_THIS(); _this->set_nodes_infos(values); } //------------------------------------------------------------------------- PyObject *pygc_get_node_info(PyObject *self, PyObject *py_node_idx) { GET_THIS(); if ( _this != NULL ) return _this->get_node_info(py_node_idx); else Py_RETURN_NONE; } //------------------------------------------------------------------------- void pygc_del_nodes_infos(PyObject *self, PyObject *py_nodes) { CHK_THIS(); _this->del_nodes_infos(py_nodes); } //------------------------------------------------------------------------- PyObject *pygc_get_current_renderer_type(PyObject *self) { GET_THIS(); if ( _this != NULL ) return _this->get_current_renderer_type(); else Py_RETURN_NONE; } //------------------------------------------------------------------------- void pygc_set_current_renderer_type(PyObject *self, PyObject *py_rt) { CHK_THIS(); _this->set_current_renderer_type(py_rt); } //------------------------------------------------------------------------- PyObject *pygc_create_groups(PyObject *self, PyObject *groups_infos) { CHK_THIS_OR_NONE(); return _this->create_groups(groups_infos); } //------------------------------------------------------------------------- PyObject *pygc_delete_groups(PyObject *self, PyObject *groups, PyObject *new_current) { CHK_THIS_OR_NONE(); return _this->delete_groups(groups, new_current); } //------------------------------------------------------------------------- PyObject *pygc_set_groups_visibility(PyObject *self, PyObject *groups, PyObject *expand, PyObject *new_current) { CHK_THIS_OR_NONE(); return _this->set_groups_visibility(groups, expand, new_current); } //------------------------------------------------------------------------- TForm *pycim_get_tform(PyObject *self) { CHK_THIS_OR_NULL(); TForm *form = NULL; if ( !py_customidamemo_t::lookup_info.find_by_py_view(&form, NULL, _this) ) return NULL; return form; } //------------------------------------------------------------------------- TCustomControl *pycim_get_tcustom_control(PyObject *self) { CHK_THIS_OR_NULL(); TCustomControl *tcc = NULL; if ( !py_customidamemo_t::lookup_info.find_by_py_view(NULL, &tcc, _this) ) return NULL; return tcc; } #undef CHK_THIS_OR_NONE #undef CHK_THIS_OR_NULL #undef CHK_THIS #undef GET_THIS //------------------------------------------------------------------------- lookup_info_t py_customidamemo_t::lookup_info; // %} %inline %{ // void pygc_refresh(PyObject *self); void pygc_set_node_info(PyObject *self, PyObject *py_node_idx, PyObject *py_node_info, PyObject *py_flags); void pygc_set_nodes_infos(PyObject *self, PyObject *values); PyObject *pygc_get_node_info(PyObject *self, PyObject *py_node_idx); void pygc_del_nodes_infos(PyObject *self, PyObject *py_nodes); PyObject *pygc_get_current_renderer_type(PyObject *self); void pygc_set_current_renderer_type(PyObject *self, PyObject *py_rt); PyObject *pygc_create_groups(PyObject *self, PyObject *groups_infos); PyObject *pygc_delete_groups(PyObject *self, PyObject *groups, PyObject *new_current); PyObject *pygc_set_groups_visibility(PyObject *self, PyObject *groups, PyObject *expand, PyObject *new_current); TForm *pycim_get_tform(PyObject *self); TCustomControl *pycim_get_tcustom_control(PyObject *self); // %} %pythoncode %{ # class CustomIDAMemo(object): def Refresh(self): """ Refreshes the graph. This causes the OnRefresh() to be called """ _idaapi.pygc_refresh(self) def GetCurrentRendererType(self): return _idaapi.pygc_get_current_renderer_type(self) def SetCurrentRendererType(self, rtype): """ Set the current view's renderer. @param rtype: The renderer type. Should be one of the idaapi.TCCRT_* values. """ _idaapi.pygc_set_current_renderer_type(self, rtype) def SetNodeInfo(self, node_index, node_info, flags): """ Set the properties for the given node. Example usage (set second nodes's bg color to red): inst = ... p = idaapi.node_info_t() p.bg_color = 0x00ff0000 inst.SetNodeInfo(1, p, idaapi.NIF_BG_COLOR) @param node_index: The node index. @param node_info: An idaapi.node_info_t instance. @param flags: An OR'ed value of NIF_* values. """ _idaapi.pygc_set_node_info(self, node_index, node_info, flags) def SetNodesInfos(self, values): """ Set the properties for the given nodes. Example usage (set first three nodes's bg color to purple): inst = ... p = idaapi.node_info_t() p.bg_color = 0x00ff00ff inst.SetNodesInfos({0 : p, 1 : p, 2 : p}) @param values: A dictionary of 'int -> node_info_t' objects. """ _idaapi.pygc_set_nodes_infos(self, values) def GetNodeInfo(self, node): """ Get the properties for the given node. @param node: The index of the node. @return: A tuple (bg_color, frame_color, ea, text), or None. """ return _idaapi.pygc_get_node_info(self, node) def DelNodesInfos(self, *nodes): """ Delete the properties for the given node(s). @param nodes: A list of node IDs """ return _idaapi.pygc_del_nodes_infos(self, nodes) def CreateGroups(self, groups_infos): """ Send a request to modify the graph by creating a (set of) group(s), and perform an animation. Each object in the 'groups_infos' list must be of the format: { "nodes" : [, , , ...] # The list of nodes to group "text" : # The synthetic text for that group } @param groups_infos: A list of objects that describe those groups. @return: A [, , ...] list of group nodes, or None (failure). """ return _idaapi.pygc_create_groups(self, groups_infos) def DeleteGroups(self, groups, new_current = -1): """ Send a request to delete the specified groups in the graph, and perform an animation. @param groups: A list of group node numbers. @param new_current: A node to focus on after the groups have been deleted @return: True on success, False otherwise. """ return _idaapi.pygc_delete_groups(self, groups, new_current) def SetGroupsVisibility(self, groups, expand, new_current = -1): """ Send a request to expand/collapse the specified groups in the graph, and perform an animation. @param groups: A list of group node numbers. @param expand: True to expand the group, False otherwise. @param new_current: A node to focus on after the groups have been expanded/collapsed. @return: True on success, False otherwise. """ return _idaapi.pygc_set_groups_visibility(self, groups, expand, new_current) def GetTForm(self): """ Return the TForm hosting this view. @return: The TForm that hosts this view, or None. """ return _idaapi.pycim_get_tform(self) def GetTCustomControl(self): """ Return the TCustomControl underlying this view. @return: The TCustomControl underlying this view, or None. """ return _idaapi.pycim_get_tcustom_control(self) # %} %{ // class py_idaview_t : public py_customidamemo_t { typedef py_customidamemo_t inherited; public: static bool Bind(PyObject *self); static bool Unbind(PyObject *self); }; //------------------------------------------------------------------------- bool py_idaview_t::Bind(PyObject *self) { // Already a py_idaview_t associated to this object? py_idaview_t *_this = view_extract_this(self); if ( _this != NULL ) return false; qstring title; if ( !PyW_GetStringAttr(self, S_M_TITLE, &title) ) return false; // Get the IDAView associated to this TForm TForm *tform = find_tform(title.c_str()); if ( tform == NULL ) return false; TCustomControl *v = get_tform_idaview(tform); if ( v == NULL ) return false; // Get unique py_idaview_t associated to that tform py_idaview_t *py_view; TCustomControl *found_view; if ( lookup_info.find_by_form(&found_view, (py_customidamemo_t**) &py_view, tform) ) { // If we have a py_idaview_t for that form, ensure it has // the expected view. QASSERT(30451, found_view == v); } else { py_view = new py_idaview_t(); lookup_info_t::entry_t &e = lookup_info.new_entry(py_view); lookup_info.commit(e, tform, v); } // Finally, bind: // py_idaview_t <=> IDAViewWrapper // py_idaview_t => TCustomControl bool ok = py_view->bind(self, v); if ( ok ) { ok = py_view->collect_pyobject_callbacks(self); if ( ok ) py_view->install_custom_viewer_handlers(); else delete py_view; } return ok; } //------------------------------------------------------------------------- bool py_idaview_t::Unbind(PyObject *self) { py_idaview_t *_this = view_extract_this(self); if ( _this == NULL ) return false; _this->unbind(); return true; } //------------------------------------------------------------------------- bool pyidag_bind(PyObject *self) { return py_idaview_t::Bind(self); } //------------------------------------------------------------------------- bool pyidag_unbind(PyObject *self) { return py_idaview_t::Unbind(self); } // %} %inline %{ // bool pyidag_bind(PyObject *self); bool pyidag_unbind(PyObject *self); // %} %pythoncode %{ # class IDAViewWrapper(CustomIDAMemo): """This class wraps access to native IDA views. See kernwin.hpp file""" def __init__(self, title): """ Constructs the IDAViewWrapper object around the view whose title is 'title'. @param title: The title of the existing IDA view. E.g., 'IDA View-A' """ self._title = title def Bind(self): return _idaapi.pyidag_bind(self) def Unbind(self): return _idaapi.pyidag_unbind(self) # %}