From 60e02ad6a81bc30d99c3f803893a88515b237c4e Mon Sep 17 00:00:00 2001 From: Willem Jan Palenstijn Date: Sat, 6 Jun 2009 11:38:20 +0000 Subject: Store long-term pointers to object variables in a new ObjVarRef struct. Storing them as reg_t* could cause the pointers to become invalid when they pointed into CloneTable since CloneTable can be re-allocated. svn-id: r41220 --- engines/sci/engine/gc.cpp | 2 +- engines/sci/engine/kgraphics.cpp | 50 ++++++++++++++++++++---------------- engines/sci/engine/kscripts.cpp | 8 +++--- engines/sci/engine/memobj.h | 4 ++- engines/sci/engine/scriptdebug.cpp | 6 ++--- engines/sci/engine/vm.cpp | 34 ++++++++++++++++-------- engines/sci/engine/vm.h | 30 ++++++++++++++++------ engines/sci/gfx/gfx_state_internal.h | 3 ++- engines/sci/gfx/gfx_widgets.cpp | 10 ++++---- engines/sci/gfx/gfx_widgets.h | 2 +- 10 files changed, 91 insertions(+), 58 deletions(-) (limited to 'engines/sci') diff --git a/engines/sci/engine/gc.cpp b/engines/sci/engine/gc.cpp index 24a7fbd1a9..1bfb66987e 100644 --- a/engines/sci/engine/gc.cpp +++ b/engines/sci/engine/gc.cpp @@ -106,7 +106,7 @@ reg_t_hash_map *find_all_used_references(EngineState *s) { wm.push(es.objp); wm.push(es.sendp); if (es.type == EXEC_STACK_TYPE_VARSELECTOR) - wm.push(*(es.addr.varp)); + wm.push(*(es.getVarPointer(s))); } } #ifdef DEBUG_GC_VERBOSE diff --git a/engines/sci/engine/kgraphics.cpp b/engines/sci/engine/kgraphics.cpp index e58fc79244..1f35f6ed04 100644 --- a/engines/sci/engine/kgraphics.cpp +++ b/engines/sci/engine/kgraphics.cpp @@ -1698,7 +1698,8 @@ static void draw_obj_to_control_map(EngineState *s, GfxDynView *view) { if (!is_object(s, obj)) warning("View %d does not contain valid object reference %04x:%04x", view->_ID, PRINT_REG(obj)); - if (!(view->signalp && (((reg_t *)view->signalp)->offset & _K_VIEW_SIG_FLAG_IGNORE_ACTOR))) { + reg_t* sp = view->signalp.getPointer(s); + if (!(sp && (sp->offset & _K_VIEW_SIG_FLAG_IGNORE_ACTOR))) { Common::Rect abs_zone = get_nsrect(s, make_reg(view->_ID, view->_subID), 1); draw_rect_to_control_map(s, abs_zone); } @@ -1749,8 +1750,9 @@ static void _k_view_list_do_postdraw(EngineState *s, GfxList *list) { fprintf(stderr, "obj %04x:%04x has pflags %x\n", PRINT_REG(obj), (widget->signal & (_K_VIEW_SIG_FLAG_REMOVE | _K_VIEW_SIG_FLAG_NO_UPDATE))); #endif - if (widget->signalp) { - *((reg_t *)(widget->signalp)) = make_reg(0, widget->signal & 0xffff); /* Write back signal */ + reg_t* sp = widget->signalp.getPointer(s); + if (sp) { + *sp = make_reg(0, widget->signal & 0xffff); /* Write back signal */ } widget = (GfxDynView *)widget->_next; @@ -1765,7 +1767,7 @@ void _k_view_list_mark_free(EngineState *s, reg_t off) { while (w) { if (w->_ID == off.segment && w->_subID == off.offset) { - w->under_bitsp = NULL; + w->under_bitsp.obj = NULL_REG; } w = (GfxDynView *)w->_next; @@ -1792,7 +1794,7 @@ int _k_view_list_dispose_loop(EngineState *s, List *list, GfxDynView *widget, in return -1; if (GFXW_IS_DYN_VIEW(widget) && (widget->_ID != GFXW_NO_ID)) { - signal = ((reg_t *)widget->signalp)->offset; + signal = widget->signalp.getPointer(s)->offset; if (signal & _K_VIEW_SIG_FLAG_DISPOSE_ME) { reg_t obj = make_reg(widget->_ID, widget->_subID); reg_t under_bits = NULL_REG; @@ -1800,20 +1802,21 @@ int _k_view_list_dispose_loop(EngineState *s, List *list, GfxDynView *widget, in if (!is_object(s, obj)) { error("Non-object %04x:%04x present in view list during delete time", PRINT_REG(obj)); obj = NULL_REG; - } else - if (widget->under_bitsp) { // Is there a bg picture left to clean? - reg_t mem_handle = *((reg_t*)(widget->under_bitsp)); + } else { + reg_t *ubp = widget->under_bitsp.getPointer(s); + if (ubp) { // Is there a bg picture left to clean? + reg_t mem_handle = *ubp; if (mem_handle.segment) { if (!kfree(s, mem_handle)) { - *((reg_t*)(widget->under_bitsp)) = make_reg(0, widget->under_bits = 0); + *ubp = make_reg(0, widget->under_bits = 0); } else { warning("Treating viewobj %04x:%04x as no longer present", PRINT_REG(obj)); obj = NULL_REG; } } } - + } if (is_object(s, obj)) { if (invoke_selector(INV_SEL(obj, delete_, kContinueOnInvalidSelector), 0)) warning("Object at %04x:%04x requested deletion, but does not have a delete funcselector", PRINT_REG(obj)); @@ -1822,11 +1825,12 @@ int _k_view_list_dispose_loop(EngineState *s, List *list, GfxDynView *widget, in return dropped; } - if (widget->under_bitsp) - under_bits = *((reg_t*)(widget->under_bitsp)); + reg_t *ubp = widget->under_bitsp.getPointer(s); + if (ubp) + under_bits = *ubp; if (under_bits.segment) { - *((reg_t*)(widget->under_bitsp)) = make_reg(0, 0); + *ubp = make_reg(0, 0); graph_restore_box(s, under_bits); } @@ -1871,7 +1875,6 @@ static GfxDynView *_k_make_dynview_obj(EngineState *s, reg_t obj, int options, i int palette; int signal; reg_t under_bits; - reg_t *under_bitsp, *signalp; Common::Point pos; int z; GfxDynView *widget; @@ -1913,19 +1916,21 @@ static GfxDynView *_k_make_dynview_obj(EngineState *s, reg_t obj, int options, i PUT_SEL32V(obj, cel, cel); } + ObjVarRef under_bitsp; if (lookup_selector(s, obj, s->_kernel->_selectorMap.underBits, &(under_bitsp), NULL) != kSelectorVariable) { - under_bitsp = NULL; + under_bitsp.obj = NULL_REG; under_bits = NULL_REG; debugC(2, kDebugLevelGraphics, "Object at %04x:%04x has no underBits\n", PRINT_REG(obj)); } else - under_bits = *((reg_t *)under_bitsp); + under_bits = *under_bitsp.getPointer(s); + ObjVarRef signalp; if (lookup_selector(s, obj, s->_kernel->_selectorMap.signal, &(signalp), NULL) != kSelectorVariable) { - signalp = NULL; + signalp.obj = NULL_REG; signal = 0; debugC(2, kDebugLevelGraphics, "Object at %04x:%04x has no signal selector\n", PRINT_REG(obj)); } else { - signal = signalp->offset; + signal = signalp.getPointer(s)->offset; debugC(2, kDebugLevelGraphics, " with signal = %04x\n", signal); } @@ -2000,8 +2005,9 @@ static void _k_make_view_list(EngineState *s, GfxList **widget_list, List *list, widget = (GfxDynView *)(*widget_list)->_contents; while (widget) { // Read back widget values - if (widget->signalp) - widget->signal = ((reg_t *)(widget->signalp))->offset; + reg_t *sp = widget->signalp.getPointer(s); + if (sp) + widget->signal = sp->offset; widget = (GfxDynView *)widget->_next; } @@ -2227,7 +2233,7 @@ void _k_draw_view_list(EngineState *s, GfxList *list, int flags) { widget = gfxw_picviewize_dynview(widget); if (GFXW_IS_DYN_VIEW(widget) && widget->_ID) { - uint16 signal = (flags & _K_DRAW_VIEW_LIST_USE_SIGNAL) ? ((reg_t *)(widget->signalp))->offset : 0; + uint16 signal = (flags & _K_DRAW_VIEW_LIST_USE_SIGNAL) ? widget->signalp.getPointer(s)->offset : 0; if (signal & _K_VIEW_SIG_FLAG_HIDDEN) gfxw_hide_widget(widget); @@ -2247,7 +2253,7 @@ void _k_draw_view_list(EngineState *s, GfxList *list, int flags) { else gfxw_show_widget(widget); - *((reg_t *)(widget->signalp)) = make_reg(0, signal); // Write the changes back + *widget->signalp.getPointer(s) = make_reg(0, signal); // Write the changes back }; } // ...if we're drawing disposeables and this one is disposeable, or if we're drawing non- diff --git a/engines/sci/engine/kscripts.cpp b/engines/sci/engine/kscripts.cpp index e400cb0827..3d516a7073 100644 --- a/engines/sci/engine/kscripts.cpp +++ b/engines/sci/engine/kscripts.cpp @@ -32,16 +32,16 @@ namespace Sci { reg_t read_selector(EngineState *s, reg_t object, Selector selector_id, const char *file, int line) { - reg_t *address; + ObjVarRef address; if (lookup_selector(s, object, selector_id, &address, NULL) != kSelectorVariable) return NULL_REG; else - return *address; + return *address.getPointer(s); } void write_selector(EngineState *s, reg_t object, Selector selector_id, reg_t value, const char *fname, int line) { - reg_t *address; + ObjVarRef address; if ((selector_id < 0) || (selector_id > (int)s->_kernel->getSelectorNamesSize())) { warning("Attempt to write to invalid selector %d of" @@ -53,7 +53,7 @@ void write_selector(EngineState *s, reg_t object, Selector selector_id, reg_t va warning("Selector '%s' of object at %04x:%04x could not be" " written to (%s L%d)", s->_kernel->getSelectorName(selector_id).c_str(), PRINT_REG(object), fname, line); else - *address = value; + *address.getPointer(s) = value; } int invoke_selector(EngineState *s, reg_t object, int selector_id, SelectorInvocation noinvalid, int kfunct, diff --git a/engines/sci/engine/memobj.h b/engines/sci/engine/memobj.h index c006caaddc..f800695df5 100644 --- a/engines/sci/engine/memobj.h +++ b/engines/sci/engine/memobj.h @@ -166,9 +166,11 @@ public: /** This struct is used to buffer the list of send calls in send_selector() */ struct CallsStruct { + reg_t addr_func; + reg_t varp_objp; union { reg_t func; - reg_t *var; + ObjVarRef var; } address; StackPtr argp; int argc; diff --git a/engines/sci/engine/scriptdebug.cpp b/engines/sci/engine/scriptdebug.cpp index 26ba01b440..64ab86a3e1 100644 --- a/engines/sci/engine/scriptdebug.cpp +++ b/engines/sci/engine/scriptdebug.cpp @@ -413,7 +413,6 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod int stackframe = (scr[pos.offset + 1] >> 1) + restmod; reg_t *sb = *p_sp; uint16 selector; - reg_t *val_ref; reg_t fun_ref; while (stackframe > 0) { @@ -435,7 +434,7 @@ reg_t disassemble(EngineState *s, reg_t pos, int print_bw_tag, int print_bytecod sciprintf(" %s::%s[", name, (selector > s->_kernel->getSelectorNamesSize()) ? "" : selector_name(s, selector)); - switch (lookup_selector(s, called_obj_addr, selector, &val_ref, &fun_ref)) { + switch (lookup_selector(s, called_obj_addr, selector, 0, &fun_ref)) { case kSelectorMethod: sciprintf("FUNCT"); argc += restmod; @@ -597,7 +596,6 @@ static int c_send(EngineState *s, const Common::Array &cmdParams) { unsigned int i; ExecStack *xstack; Object *o; - reg_t *vptr; reg_t fptr; selector_id = s->_kernel->findSelector(selector_name); @@ -613,7 +611,7 @@ static int c_send(EngineState *s, const Common::Array &cmdParams) { return 1; } - SelectorType selector_type = lookup_selector(s, object, selector_id, &vptr, &fptr); + SelectorType selector_type = lookup_selector(s, object, selector_id, 0, &fptr); if (selector_type == kSelectorNone) { sciprintf("Object does not support selector: \"%s\"\n", selector_name); diff --git a/engines/sci/engine/vm.cpp b/engines/sci/engine/vm.cpp index fd8ce33f51..7b5fe3396a 100644 --- a/engines/sci/engine/vm.cpp +++ b/engines/sci/engine/vm.cpp @@ -280,10 +280,10 @@ static void _exec_varselectors(EngineState *s) { ExecStack &xs = s->_executionStack.back(); // varselector access? if (xs.argc) { // write? - *(xs.addr.varp) = xs.variables_argp[1]; + *(xs.getVarPointer(s)) = xs.variables_argp[1]; } else // No, read - s->r_acc = *(xs.addr.varp); + s->r_acc = *(xs.getVarPointer(s)); s->_executionStack.pop_back(); } @@ -294,7 +294,6 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt // Returns a pointer to the TOS exec_stack element assert(s); - reg_t *varp; reg_t funcp; int selector; int argc; @@ -341,6 +340,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt sciprintf("Send to %04x:%04x, selector %04x (%s):", PRINT_REG(send_obj), selector, s->_selectorNames[selector].c_str()); #endif // VM_DEBUG_SEND + ObjVarRef varp; switch (lookup_selector(s, send_obj, selector, &varp, &funcp)) { case kSelectorNone: // WORKAROUND: LSL6 tries to access the invalid 'keep' selector of the game object. @@ -377,7 +377,7 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt #endif { // Argument is supplied -> Selector should be set if (print_send_action) { - reg_t oldReg = *varp; + reg_t oldReg = *varp.getPointer(s); reg_t newReg = argp[1]; sciprintf("[write to selector: change %04x:%04x to %04x:%04x]\n", PRINT_REG(oldReg), PRINT_REG(newReg)); @@ -454,8 +454,8 @@ ExecStack *send_selector(EngineState *s, reg_t send_obj, reg_t work_obj, StackPt return &(s->_executionStack.back()); } -ExecStack *add_exec_stack_varselector(EngineState *s, reg_t objp, int argc, StackPtr argp, Selector selector, reg_t *address, int origin) { - ExecStack *xstack = add_exec_stack_entry(s, NULL_REG, address, objp, argc, argp, selector, objp, origin, SCI_XS_CALLEE_LOCALS); +ExecStack *add_exec_stack_varselector(EngineState *s, reg_t objp, int argc, StackPtr argp, Selector selector, const ObjVarRef& address, int origin) { + ExecStack *xstack = add_exec_stack_entry(s, NULL_REG, 0, objp, argc, argp, selector, objp, origin, SCI_XS_CALLEE_LOCALS); // Store selector address in sp xstack->addr.varp = address; @@ -1048,9 +1048,9 @@ void run_vm(EngineState *s, int restoring) { if (old_xs->type == EXEC_STACK_TYPE_VARSELECTOR) { // varselector access? if (old_xs->argc) // write? - *(old_xs->addr.varp) = old_xs->variables_argp[1]; + *(old_xs->getVarPointer(s)) = old_xs->variables_argp[1]; else // No, read - s->r_acc = *(old_xs->addr.varp); + s->r_acc = *(old_xs->getVarPointer(s)); } // Not reached the base, so let's do a soft return @@ -1507,7 +1507,7 @@ static SelectorType _lookup_selector_function(EngineState *s, int seg_id, Object return kSelectorNone; } -SelectorType lookup_selector(EngineState *s, reg_t obj_location, Selector selector_id, reg_t **vptr, reg_t *fptr) { +SelectorType lookup_selector(EngineState *s, reg_t obj_location, Selector selector_id, ObjVarRef *varp, reg_t *fptr) { Object *obj = obj_get(s, obj_location); Object *species; int index; @@ -1540,8 +1540,10 @@ SelectorType lookup_selector(EngineState *s, reg_t obj_location, Selector select if (index >= 0) { // Found it as a variable - if (vptr) - *vptr = &obj->_variables[index]; + if (varp) { + varp->obj = obj_location; + varp->varindex = index; + } return kSelectorVariable; } @@ -2075,5 +2077,15 @@ void shrink_execution_stack(EngineState *s, uint size) { s->_executionStack.erase(iter, s->_executionStack.end()); } +reg_t* ObjVarRef::getPointer(EngineState *s) const { + Object *o = obj_get(s, obj); + if (!o) return 0; + return &(o->_variables[varindex]); +} + +reg_t* ExecStack::getVarPointer(EngineState *s) const { + assert(type == EXEC_STACK_TYPE_VARSELECTOR); + return addr.varp.getPointer(s); +} } // End of namespace Sci diff --git a/engines/sci/engine/vm.h b/engines/sci/engine/vm.h index 5bfbe71ce9..dfbbc39780 100644 --- a/engines/sci/engine/vm.h +++ b/engines/sci/engine/vm.h @@ -201,10 +201,20 @@ struct selector_map_t { Selector syncTime; /**< Used by DoSync() */ }; +// A reference to an object's variable. +// The object is stored as a reg_t, the variable as an index into _variables +struct ObjVarRef { + reg_t obj; + int varindex; + + reg_t* getPointer(EngineState *s) const; +}; + + struct ViewObject { reg_t obj; - reg_t *signalp; /* Used only indirectly */ - reg_t *underBitsp; /* The same goes for the handle storage */ + ObjVarRef signalp; /* Used only indirectly */ + ObjVarRef underBitsp; /* The same goes for the handle storage */ int underBits; /* Copy of the underbits: Needed for cleanup */ int x, y; @@ -231,10 +241,12 @@ enum ExecStackType { struct ExecStack { reg_t objp; reg_t sendp; /**< Pointer to the object containing the invoked method */ + union { - reg_t *varp; /**< Variable pointer for read/write access */ + ObjVarRef varp; /**< Variable pointer for r/w access */ reg_t pc; /**< Not accurate for the TOS element */ } addr; + StackPtr fp; /**< Frame pointer */ StackPtr sp; /**< Stack pointer */ int argc; @@ -246,6 +258,8 @@ struct ExecStack { Selector selector; /**< The selector which was used to call or -1 if not applicable */ int origin; /**< The stack frame position the call was made from, or -1 if it was the initial call. */ ExecStackType type; + + reg_t* getVarPointer(EngineState *s) const; }; @@ -355,13 +369,13 @@ ExecStack *add_exec_stack_entry(EngineState *s, reg_t pc, StackPtr sp, reg_t obj * (int) argc: 1 for writing, 0 for reading * (StackPtr) argp: Pointer to the address of the data to write -2 * (int) selector: Selector name - * (reg_t *) address: Heap address of the selector + * (ObjVarRef& ) address: Heap address of the selector * (int) origin: Stack frame which the access originated from * Returns : (ExecStack *): Pointer to the new exec-TOS element * This function is called from send_selector only. */ ExecStack *add_exec_stack_varselector(EngineState *s, reg_t objp, int argc, StackPtr argp, - Selector selector, reg_t *address, int origin); + Selector selector, const ObjVarRef& address, int origin); void run_vm(EngineState *s, int restoring); @@ -428,7 +442,7 @@ void script_free_vm_memory(EngineState *s); */ -SelectorType lookup_selector(EngineState *s, reg_t obj, Selector selectorid, reg_t **vptr, reg_t *fptr); +SelectorType lookup_selector(EngineState *s, reg_t obj, Selector selectorid, ObjVarRef *varp, reg_t *fptr); /* Looks up a selector and returns its type and value ** Parameters: (EngineState *) s: The EngineState to use ** (reg_t) obj: Address of the object to look the selector up in @@ -436,11 +450,11 @@ SelectorType lookup_selector(EngineState *s, reg_t obj, Selector selectorid, reg ** Returns : (SelectorType) kSelectorNone if the selector was not found in the object or its superclasses. ** kSelectorVariable if the selector represents an object-relative variable ** kSelectorMethod if the selector represents a method -** (reg_t *) *vptr: A pointer to the storage space associated with the selector, if +** (ObjVarRef *) *varp: A reference to the selector, if ** it is a variable ** (reg_t) *fptr: A reference to the function described by that selector, if it is ** a valid function selector. -** *vptr is written to iff it is non-NULL and the selector indicates a property of the object. +** *varindex is written to iff it is non-NULL and the selector indicates a property of the object. ** *fptr is written to iff it is non-NULL and the selector indicates a member function of that object. */ diff --git a/engines/sci/gfx/gfx_state_internal.h b/engines/sci/gfx/gfx_state_internal.h index c184492054..d03c5e9519 100644 --- a/engines/sci/gfx/gfx_state_internal.h +++ b/engines/sci/gfx/gfx_state_internal.h @@ -245,7 +245,8 @@ public: struct GfxDynView : public GfxView { /* FIXME: This code is specific to SCI */ rect_t draw_bounds; /* The correct position to draw to */ - void *under_bitsp, *signalp; + ObjVarRef under_bitsp; + ObjVarRef signalp; int under_bits, signal; int _z; /**< The z coordinate: Added to y, but used for sorting */ int sequence; /**< Sequence number: For sorting */ diff --git a/engines/sci/gfx/gfx_widgets.cpp b/engines/sci/gfx/gfx_widgets.cpp index 08600c94b2..635490da76 100644 --- a/engines/sci/gfx/gfx_widgets.cpp +++ b/engines/sci/gfx/gfx_widgets.cpp @@ -681,10 +681,10 @@ int GfxDynView::draw(const Common::Point &pos) { else error("GfxDynView::print: Invalid type %d", _type); - sciprintf(" SORT=%d z=%d seq=%d (%d/%d/%d)@(%d,%d)[p:%d,c:%d]; sig[%04x@%p]", force_precedence, _z, + sciprintf(" SORT=%d z=%d seq=%d (%d/%d/%d)@(%d,%d)[p:%d,c:%d]; sig[%04x@%04X:%04X[%d]]", force_precedence, _z, sequence, _view, _loop, _cel, _pos.x, _pos.y, (_color.mask & GFX_MASK_PRIORITY) ? _color.priority : -1, - (_color.mask & GFX_MASK_CONTROL) ? _color.control : -1, signal, signalp); + (_color.mask & GFX_MASK_CONTROL) ? _color.control : -1, signal, signalp.obj.segment, signalp.obj.offset, signalp.varindex); } static int _gfxwop_dyn_view_equals(GfxWidget *widget, GfxWidget *other) { @@ -794,9 +794,9 @@ GfxDynView::GfxDynView(GfxState *state, Common::Point pos_, int z_, int view_, i draw_bounds = gfx_rect(_pos.x - xalignmod, _pos.y - yalignmod - z_, width, height); _bounds = gfx_rect(_pos.x - offset.x - xalignmod, _pos.y - offset.y - yalignmod - z_, width, height); - under_bitsp = NULL; + under_bitsp.obj = NULL_REG; under_bits = 0; - signalp = NULL; + signalp.obj = NULL_REG; signal = 0; _z = z_; sequence = sequence_; @@ -1671,7 +1671,7 @@ GfxWidget *gfxw_set_id(GfxWidget *widget, int ID, int subID) { return widget; } -GfxDynView *gfxw_dyn_view_set_params(GfxDynView *widget, int under_bits, void *under_bitsp, int signal, void *signalp) { +GfxDynView *gfxw_dyn_view_set_params(GfxDynView *widget, int under_bits, const ObjVarRef& under_bitsp, int signal, const ObjVarRef& signalp) { if (!widget) return NULL; diff --git a/engines/sci/gfx/gfx_widgets.h b/engines/sci/gfx/gfx_widgets.h index 6c8e848664..bd884ffbb4 100644 --- a/engines/sci/gfx/gfx_widgets.h +++ b/engines/sci/gfx/gfx_widgets.h @@ -271,7 +271,7 @@ GfxWidget *gfxw_remove_id(GfxContainer *container, int ID, int subID); */ -GfxDynView *gfxw_dyn_view_set_params(GfxDynView *widget, int under_bits, void *under_bitsp, int signal, void *signalp); +GfxDynView *gfxw_dyn_view_set_params(GfxDynView *widget, int under_bits, const ObjVarRef& under_bitsp, int signal, const ObjVarRef& signalp); /* Initializes a dyn view's interpreter attributes ** Parameters: (GfxDynView *) widget: The widget affected ** (int x void * x int x void *) under_bits, inder_bitsp, signal, signalp: Interpreter-dependant data -- cgit v1.2.3