Skip to content
Snippets Groups Projects
FXRuby.cpp 63.6 KiB
Newer Older
    case SEL_MINIMIZE:
    case SEL_RESTORE:
    case SEL_MAXIMIZE:
    case SEL_UPDATE:
    case SEL_QUERY_TIP:
    case SEL_QUERY_HELP:
      return NULL;
    case SEL_VERIFY:
      return reinterpret_cast<void*>(StringValuePtr(value));
    case SEL_CLICKED:
    case SEL_DOUBLECLICKED:
    case SEL_TRIPLECLICKED:
    case SEL_CHANGED:
    case SEL_DESELECTED:
    case SEL_SELECTED:
    case SEL_INSERTED:
    case SEL_REPLACED:
    case SEL_DELETED:
    case SEL_OPENED:
    case SEL_CLOSED:
    case SEL_EXPANDED:
    case SEL_COLLAPSED:
      return NULL;
    default:
      /* Ignore */
      break;
    }
  if(type==SEL_COMMAND){
    // Handle FXText-specific messages
    if(obj->isMemberOf(FXMETACLASS(FXText))){
      switch(id){
        case FXText::ID_COPY_SEL:
        case FXText::ID_PASTE_SEL:
        case FXText::ID_DELETE_SEL:
          return NULL;
        default:
          break;
        }
      }

    // Handle FXTextField-specific message
    if(obj->isMemberOf(FXMETACLASS(FXTextField))){
      switch(id){
        case FXTextField::ID_INSERT_STRING:
          return reinterpret_cast<void*>(StringValuePtr(value));;
        default:
          break;
        }
      }

    // Handle messages applicable to all FXWindow descendants
    if(obj->isMemberOf(FXMETACLASS(FXWindow))){
      switch(id){
        case FXWindow::ID_HIDE:
        case FXWindow::ID_SHOW:
        case FXWindow::ID_TOGGLESHOWN:
        case FXWindow::ID_LOWER:
        case FXWindow::ID_RAISE:
        case FXWindow::ID_DELETE:
        case FXWindow::ID_DISABLE:
        case FXWindow::ID_ENABLE:
        case FXWindow::ID_UNCHECK:
        case FXWindow::ID_CHECK:
        case FXWindow::ID_UNKNOWN:
        case FXWindow::ID_UPDATE:
        case FXWindow::ID_AUTOSCROLL:
        case FXWindow::ID_QUERY_MENU:
        case FXWindow::ID_HOTKEY:
        case FXWindow::ID_ACCEL:
        case FXWindow::ID_UNPOST:
        case FXWindow::ID_POST:
        case FXWindow::ID_MDI_TILEHORIZONTAL:
        case FXWindow::ID_MDI_TILEVERTICAL:
        case FXWindow::ID_MDI_CASCADE:
        case FXWindow::ID_MDI_MAXIMIZE:
        case FXWindow::ID_MDI_MINIMIZE:
        case FXWindow::ID_MDI_RESTORE:
        case FXWindow::ID_MDI_CLOSE:
        case FXWindow::ID_MDI_WINDOW:
        case FXWindow::ID_MDI_MENUWINDOW:
        case FXWindow::ID_MDI_MENUMINIMIZE:
        case FXWindow::ID_MDI_MENURESTORE:
        case FXWindow::ID_MDI_MENUCLOSE:
        case FXWindow::ID_MDI_NEXT:
        case FXWindow::ID_MDI_PREV:
          return NULL;
        case FXWindow::ID_SETVALUE:
          if(obj->isMemberOf(FXMETACLASS(FXButton)) ||
             obj->isMemberOf(FXMETACLASS(FXCheckButton)) ||
             obj->isMemberOf(FXMETACLASS(FXDial)) ||
             obj->isMemberOf(FXMETACLASS(FXRadioButton)) ||
             obj->isMemberOf(FXMETACLASS(FXShutter)) ||
             obj->isMemberOf(FXMETACLASS(FXSpinner)) ||
             obj->isMemberOf(FXMETACLASS(FXTabBar)) ||
             obj->isMemberOf(FXMETACLASS(FXToggleButton)) ||
             obj->isMemberOf(FXMETACLASS(FXScrollBar)) ||
             obj->isMemberOf(FXMETACLASS(FXSlider)) ||
             obj->isMemberOf(FXMETACLASS(FXSwitcher))){
            return reinterpret_cast<void*>(static_cast<long>(NUM2INT(value)));
            }
          else if(obj->isMemberOf(FXMETACLASS(FXColorSelector)) ||
                  obj->isMemberOf(FXMETACLASS(FXColorWell))){
            return reinterpret_cast<void*>(static_cast<unsigned long>(NUM2UINT(value)));
            }
          else if(obj->isMemberOf(FXMETACLASS(FXProgressBar))){
            return reinterpret_cast<void*>(static_cast<unsigned long>(NUM2UINT(value)));
            }
          else if(obj->isMemberOf(FXMETACLASS(FXComboBox)) ||
                  obj->isMemberOf(FXMETACLASS(FXTextField)) ||
                  obj->isMemberOf(FXMETACLASS(FXDirBox)) ||
                  obj->isMemberOf(FXMETACLASS(FXDirList)) ||
                  obj->isMemberOf(FXMETACLASS(FXDriveBox)) ||
                  obj->isMemberOf(FXMETACLASS(FXFileList))){
            return reinterpret_cast<void*>(StringValuePtr(value));
            }
          else if(obj->isMemberOf(FXMETACLASS(FXMenuCheck))){
            return reinterpret_cast<void*>(static_cast<FXuval>(RTEST(value) ? 1 : 0));
            }
          else if(obj->isMemberOf(FXMETACLASS(FXMenuRadio))){
            return reinterpret_cast<void*>(static_cast<FXuval>(RTEST(value) ? 1 : 0));
          else if(obj->isMemberOf(FXMETACLASS(FXMenuCommand))){
            return reinterpret_cast<void*>(static_cast<FXuval>(RTEST(value) ? 1 : 0));
            }
          return NULL;
        case FXWindow::ID_HSCROLLED:
        case FXWindow::ID_VSCROLLED:
          return reinterpret_cast<void*>(static_cast<unsigned long>(NUM2UINT(value)));
        case FXWindow::ID_SETINTVALUE:
          if(obj->isMemberOf(FXMETACLASS(FXColorWell))){
            colorValue=NUM2UINT(value);
            return reinterpret_cast<void*>(&colorValue);
            }
          else{
            intValue=NUM2INT(value);
            return reinterpret_cast<void*>(&intValue);
            }
        case FXWindow::ID_SETREALVALUE:
          realValue=NUM2DBL(value);
          return reinterpret_cast<void*>(&realValue);
        case FXWindow::ID_SETSTRINGVALUE:
          stringValue=FXString(StringValuePtr(value));
          return reinterpret_cast<void*>(&stringValue);
        case FXWindow::ID_SETINTRANGE:
          intRange[0]=NUM2INT(rb_ary_entry(value,0));
          intRange[1]=NUM2INT(rb_ary_entry(value,1));
          return reinterpret_cast<void*>(intRange);
        case FXWindow::ID_SETREALRANGE:
          realRange[0]=NUM2DBL(rb_ary_entry(value,0));
          realRange[1]=NUM2DBL(rb_ary_entry(value,1));
          return reinterpret_cast<void*>(realRange);
        case FXWindow::ID_GETINTVALUE:
        case FXWindow::ID_GETREALVALUE:
        case FXWindow::ID_GETSTRINGVALUE:
        case FXWindow::ID_GETINTRANGE:
        case FXWindow::ID_GETREALRANGE:
          return NULL;
        default:
          // Pass this data along as-is
          break;
        }
      }
    }

  if(type==SEL_CHANGED){
	  if(obj->isMemberOf(FXMETACLASS(FXPicker))){
			SWIG_Ruby_ConvertPtr(value,&ptr,FXRbTypeQuery("FXPoint *"),1);
			return ptr;
	    }
		return 0;
    }
	
	if(type==SEL_DRAGGED){
	    SWIG_Ruby_ConvertPtr(value,&ptr,FXRbTypeQuery("FXEvent *"),1);
	    return ptr;
	    }

  // Pass through as-is
  return reinterpret_cast<void*>(value);
  }


static ID id_assocs;


/**
 * Look up the name of the message handler function for this
 * receiver and message (type, id) combination and return it;
 * or return zero if the designated receiver doesn't handle this
 * message.
 */
ID FXRbLookupHandler(FXObject* recv,FXSelector key){
  FXTRACE((100,"FXRbLookupHandler(recv=%p(%s),FXSEL(%d,%d))\n",recv,recv->getClassName(),FXSELTYPE(key),FXSELID(key)));
  ID id=0;
  VALUE rubyObj=to_ruby(recv);
  FXASSERT((recv==0 && rubyObj==Qnil) || (recv!=0 && rubyObj!=Qnil));
  if(rb_ivar_defined(rubyObj,id_assocs)==Qtrue){
    VALUE assocs=rb_ivar_get(rubyObj,id_assocs);
    VALUE entry;
    FXSelector keylo,keyhi;
    for(long i=0;i<RARRAY_LEN(assocs);i++){
      entry=rb_ary_entry(assocs,i);
      keylo=NUM2UINT(rb_ary_entry(entry,0));
      keyhi=NUM2UINT(rb_ary_entry(entry,1));
      if(keylo<=key && key<=keyhi){
        id=SYM2ID(rb_ary_entry(entry,2));
	FXASSERT(id!=0);
	break;
        }
      }
    }
  return id;
  }


struct FXRbHandleArgs {
  VALUE recv;
  VALUE id;
  int nargs;
  VALUE sender;
  VALUE key;
  VALUE data;
  };


static VALUE handle_body(VALUE args){
  FXRbHandleArgs* hArgs=reinterpret_cast<FXRbHandleArgs*>(args);
  FXASSERT(hArgs!=0);
  return rb_funcall(hArgs->recv,hArgs->id,hArgs->nargs,hArgs->sender,hArgs->key,hArgs->data);
  }


static ID id_backtrace;


static VALUE handle_rescue(VALUE args,VALUE error){
  VALUE info=rb_gv_get("$!");
  VALUE errat=rb_funcall(info,id_backtrace,0);
  VALUE mesg=RARRAY_PTR(errat)[0];
  fprintf(stderr,"%s: %s (%s)\n",
    StringValuePtr(mesg),
    RSTRING_PTR(rb_obj_as_string(info)),
    rb_class2name(CLASS_OF(info)));
  for(int i=1;i<RARRAY_LEN(errat);i++){
    if(TYPE(RARRAY_PTR(errat)[i])==T_STRING){
      fprintf(stderr,"\tfrom %s\n",StringValuePtr(RARRAY_PTR(errat)[i]));
      }
    }
  return Qnil;
  }


// Call the designated function and return its result (which should be a long).
long FXRbHandleMessage(FXObject* recv,ID func,FXObject* sender,FXSelector key,void* ptr){
  FXRbHandleArgs hArgs;
  hArgs.recv=to_ruby(recv);
  hArgs.sender=to_ruby(sender);
  hArgs.key=to_ruby(key);
  hArgs.data=FXRbConvertMessageData(sender,recv,key,ptr);
  hArgs.id=func;
  hArgs.nargs=3;
  VALUE retval;

  FXTRACE((100,"FXRbHandleMessage(recv=%p(%s),FXSEL(%s,%d)\n",recv,recv->getClassName(),FXDebugTarget::messageTypeName[FXSELTYPE(key)],FXSELID(key)));

  if(FXRbCatchExceptions){
#ifdef RB_RESCUE2_BROKEN_PROTOTYPE
    retval=rb_rescue2((VALUE(*)()) handle_body, reinterpret_cast<VALUE>(&hArgs),
                      (VALUE(*)()) handle_rescue, Qnil,
                      rb_eStandardError, rb_eNameError, 0);
#else
    retval=rb_rescue2((VALUE(*)(ANYARGS)) handle_body, reinterpret_cast<VALUE>(&hArgs),
                      (VALUE(*)(ANYARGS)) handle_rescue, Qnil,
                      rb_eStandardError, rb_eNameError, 0);
#endif
    }
  else{
    retval=handle_body(reinterpret_cast<VALUE>(&hArgs));
    }

  /**
   * Process the return value. For boolean return values, convert "true"
   * to 1 and "false" to zero. For numeric types, convert it to a long value
   * but trap the result to either 0 or 1 since these are usually what
   * FOX is looking for. For any other type result (including nil) return 1.
   * Thanks to Ted Meng for this suggestion.
   */
  long lresult;
  switch(TYPE(retval)){
    case T_TRUE:
      lresult=1;
      break;
    case T_FALSE:
      lresult=0;
      break;
    case T_BIGNUM:
      lresult=1;
      break;
    case T_FIXNUM:
    case T_FLOAT:
      lresult=(NUM2LONG(retval) == 0) ? 0 : 1; // trap any numeric result to either 0 or 1
      break;
    default:
      lresult=1;
    }
  return lresult;
  }

//----------------------------------------------------------------------

static ID id_begin;
static ID id_end;
static ID id_exclude_endp;

void FXRbRange2LoHi(VALUE range,FXint& lo,FXint& hi){
  if(Qtrue!=rb_obj_is_instance_of(range,rb_cRange)){
    rb_raise(rb_eTypeError,"wrong argument type %s (expected %s)",rb_class2name(CLASS_OF(range)),rb_class2name(rb_cRange));
    }
  else{
    VALUE beg=rb_funcall(range,id_begin,0,NULL);
    VALUE end=rb_funcall(range,id_end,0,NULL);
    VALUE excl=rb_funcall(range,id_exclude_endp,0,NULL);
    lo=NUM2INT(beg);
    hi=NUM2INT(end);
    if(excl==Qtrue){
      hi--;
      }
    }
  }

void FXRbRange2LoHi(VALUE range,FXdouble& lo,FXdouble& hi){
  if(Qtrue!=rb_obj_is_instance_of(range,rb_cRange)){
    rb_raise(rb_eTypeError,"wrong argument type %s (expected %s)",rb_class2name(CLASS_OF(range)),rb_class2name(rb_cRange));
    }
  else{
    VALUE beg=rb_funcall(range,id_begin,0,NULL);
    VALUE end=rb_funcall(range,id_end,0,NULL);
    VALUE excl=rb_funcall(range,id_exclude_endp,0,NULL);
    lo=NUM2DBL(beg);
    hi=NUM2DBL(end);
    if(excl==Qtrue){
      hi--;
      }
    }
  }
  
//----------------------------------------------------------------------

void FXRbCallVoidMethod(FXObject* recv, ID func) {
  VALUE obj=FXRbGetRubyObj(recv,false);
  FXASSERT(!NIL_P(obj));
  rb_funcall(obj,func,0,NULL);
  }

void FXRbCallVoidMethod(FXDC* recv,ID func) {
  VALUE obj=FXRbGetRubyObj(recv,false);
  FXASSERT(!NIL_P(obj));
  rb_funcall(obj,func,0,NULL);
  }

//----------------------------------------------------------------------

bool FXRbCallBoolMethod(const FXObject* recv,ID func){
  VALUE obj=FXRbGetRubyObj(recv,false);
  FXASSERT(!NIL_P(obj));
  VALUE v=rb_funcall(obj,func,0,NULL);
  return (v==Qtrue);
  }

//----------------------------------------------------------------------

// Call function with "FXint" return value
FXint FXRbCallIntMethod(const FXObject* recv,ID func){
  VALUE obj=FXRbGetRubyObj(recv,false);
  FXASSERT(!NIL_P(obj));
  VALUE result=rb_funcall(obj,func,0,NULL);
  return static_cast<FXint>(NUM2INT(result));
  }

//----------------------------------------------------------------------

// Call function with "FXGLObject*" return value
FXGLObject* FXRbCallGLObjectMethod(FXGLObject* recv,ID func){
  VALUE obj=FXRbGetRubyObj(recv,false);
  FXASSERT(!NIL_P(obj));
  VALUE result=rb_funcall(obj,func,0,NULL);
  return NIL_P(result) ? 0 : reinterpret_cast<FXGLObject*>(DATA_PTR(result));
  }

FXGLObject* FXRbCallGLObjectMethod(FXGLViewer* recv,ID func,FXint x,FXint y){
  VALUE obj=FXRbGetRubyObj(recv,false);
  FXASSERT(!NIL_P(obj));
  VALUE result=rb_funcall(obj,func,2,INT2NUM(x),INT2NUM(y));
  return NIL_P(result) ? 0 : reinterpret_cast<FXGLObject*>(DATA_PTR(result));
  }

FXGLObject* FXRbCallGLObjectMethod(FXGLObject* recv,ID func,FXuint* path,FXint n){
  VALUE obj=FXRbGetRubyObj(recv,false);
  FXASSERT(!NIL_P(obj));
  VALUE result=rb_funcall(obj,func,1,FXRbMakeArray(path,n));
  return NIL_P(result) ? 0 : reinterpret_cast<FXGLObject*>(DATA_PTR(result));
  }

//----------------------------------------------------------------------

// Call function with "FXGLObject**" return value
FXGLObject** FXRbCallGLObjectArrayMethod(FXGLViewer* recv,ID func,FXint x,FXint y,FXint w,FXint h){
  FXGLObject** objects=NULL;
  VALUE obj=FXRbGetRubyObj(recv,false);
  FXASSERT(!NIL_P(obj));
  VALUE result=rb_funcall(obj,func,4,INT2NUM(x),INT2NUM(y),INT2NUM(w),INT2NUM(h));
  if(!NIL_P(result)){
    Check_Type(result,T_ARRAY);
    if(FXMALLOC(&objects,FXGLObject*,RARRAY_LEN(result)+1)){
      for(long i=0; i<RARRAY_LEN(result); i++){
	objects[i]=reinterpret_cast<FXGLObject*>(DATA_PTR(rb_ary_entry(result,i)));
        }
      objects[RARRAY_LEN(result)]=0;
      }
    }
  return objects; // caller must free this
  }

//----------------------------------------------------------------------

FXTableItem* FXRbCallTableItemMethod(FXTable* recv,ID func,const FXString& text,FXIcon* icon,void* ptr){
  VALUE itemData=(ptr==0)?Qnil:reinterpret_cast<VALUE>(ptr);
  VALUE obj=FXRbGetRubyObj(recv,false);
  FXASSERT(!NIL_P(obj));
  VALUE result=rb_funcall(obj,func,3,to_ruby(text),to_ruby(icon),itemData);
  return NIL_P(result)?0:reinterpret_cast<FXTableItem*>(DATA_PTR(result));
  }

FXTableItem* FXRbCallTableItemMethod(FXTable* recv,ID func,FXint row,FXint col,FXbool notify){
  VALUE obj=FXRbGetRubyObj(recv,false);
  FXASSERT(!NIL_P(obj));
  VALUE result=rb_funcall(obj,func,3,to_ruby(row),to_ruby(col),to_ruby(notify));
  return NIL_P(result)?0:reinterpret_cast<FXTableItem*>(DATA_PTR(result));
  }

//----------------------------------------------------------------------

FXTreeItem* FXRbCallTreeItemMethod(const FXTreeList* recv,ID func,FXint x,FXint y){
  VALUE obj=FXRbGetRubyObj(recv,false);
  FXASSERT(!NIL_P(obj));
  VALUE result=rb_funcall(obj,func,2,INT2NUM(x),INT2NUM(y));
  return NIL_P(result) ? 0 : reinterpret_cast<FXTreeItem*>(DATA_PTR(result));
  }

//----------------------------------------------------------------------

FXFoldingItem* FXRbCallFoldingItemMethod(const FXFoldingList* recv,ID func,FXint x,FXint y){
  VALUE obj=FXRbGetRubyObj(recv,false);
  FXASSERT(!NIL_P(obj));
  VALUE result=rb_funcall(obj,func,2,INT2NUM(x),INT2NUM(y));
  return NIL_P(result) ? 0 : reinterpret_cast<FXFoldingItem*>(DATA_PTR(result));
  }

//----------------------------------------------------------------------

FXFileAssoc* FXRbCallFileAssocMethod(const FXFileDict* recv,ID func,const char* pathname){
  VALUE obj=FXRbGetRubyObj(recv,false);
  FXASSERT(!NIL_P(obj));
  VALUE result=rb_funcall(obj,func,1,rb_str_new2(pathname));
  return NIL_P(result) ? 0 : reinterpret_cast<FXFileAssoc*>(DATA_PTR(result));
  }

//----------------------------------------------------------------------

FXIcon* FXRbCallIconMethod(const FXTableItem* recv,ID func){
  VALUE obj=FXRbGetRubyObj(recv,false);
  FXASSERT(!NIL_P(obj));
	if(!NIL_P(obj)){
	  VALUE result=rb_funcall(obj,func,0,NULL);
	  return NIL_P(result) ? 0 : reinterpret_cast<FXIcon*>(DATA_PTR(result));
		}
	else{
		return 0;
		}
  }

//----------------------------------------------------------------------

FXWindow* FXRbCallWindowMethod(const FXTableItem* recv,ID func,FXTable* table){
  VALUE obj=FXRbGetRubyObj(recv,false);
  FXASSERT(!NIL_P(obj));
  VALUE result=rb_funcall(obj,func,1,to_ruby(table));
  return NIL_P(result) ? 0 : reinterpret_cast<FXWindow*>(DATA_PTR(result));
  }

//----------------------------------------------------------------------

// Call function with "FXRange" return value
FXRangef FXRbCallRangeMethod(FXObject* recv,ID func){
  VALUE obj=FXRbGetRubyObj(recv,false);
  FXASSERT(!NIL_P(obj));
  VALUE result=rb_funcall(obj,func,0,NULL);
  return *reinterpret_cast<FXRangef*>(DATA_PTR(result));
  }

//----------------------------------------------------------------------

// Call functions with FXString return value
FXString FXRbCallStringMethod(const FXObject* recv, ID func){
  VALUE obj=FXRbGetRubyObj(recv,false);
  FXASSERT(!NIL_P(obj));
  VALUE result=rb_funcall(obj,func,0,NULL);
  return FXString(StringValuePtr(result));
  }

//----------------------------------------------------------------------

// Call functions with const FXchar* return value
const FXchar* FXRbCallCStringMethod(const FXObject* recv, ID func, const FXchar* message, const FXchar* hint){
  VALUE obj=FXRbGetRubyObj(recv,false);
  FXASSERT(!NIL_P(obj));
  VALUE result=rb_funcall(obj,func,2,to_ruby(message),to_ruby(hint));
  return NIL_P(result) ? 0 : StringValuePtr(result);
  }

// Call functions with const FXchar* return value
const FXchar* FXRbCallCStringMethod(const FXObject* recv, ID func, const FXchar* context, const FXchar* message, const FXchar* hint){
  VALUE obj=FXRbGetRubyObj(recv,false);
  FXASSERT(!NIL_P(obj));
  VALUE result=rb_funcall(obj,func,3,to_ruby(context),to_ruby(message),to_ruby(hint));
  return NIL_P(result) ? 0 : StringValuePtr(result);
  }
//----------------------------------------------------------------------

// Call functions with FXwchar return value
FXwchar FXRbCallWCharMethod(const FXObject* recv, ID func){
  VALUE obj=FXRbGetRubyObj(recv,false);
  FXASSERT(!NIL_P(obj));
  VALUE result=rb_funcall(obj,func,0,NULL);
  return static_cast<FXwchar>(NUM2ULONG(result));
  }

//----------------------------------------------------------------------

// Special destructors to handle order dependencies
FXRbMenuCommand::~FXRbMenuCommand(){
  FXAccelTable *table;
  FXWindow *owner;
  if(acckey){
    owner=getShell()->getOwner();
    if(owner){
      table=owner->getAccelTable();
      if(table && table!=reinterpret_cast<FXAccelTable*>(-1)){
        table->removeAccel(acckey);
        }
      }
    }
  acckey=(FXHotKey)NULL;
  FXRbUnregisterRubyObj(this);
  }

FXRbMenuCheck::~FXRbMenuCheck(){
  FXAccelTable *table;
  FXWindow *owner;
  if(acckey){
    owner=getShell()->getOwner();
    if(owner){
      table=owner->getAccelTable();
      if(table && table!=reinterpret_cast<FXAccelTable*>(-1)){
        table->removeAccel(acckey);
        }
      }
    }
  acckey=(FXHotKey)NULL;
  FXRbUnregisterRubyObj(this);
  }

FXRbMenuRadio::~FXRbMenuRadio(){
  FXAccelTable *table;
  FXWindow *owner;
  if(acckey){
    owner=getShell()->getOwner();
    if(owner){
      table=owner->getAccelTable();
      if(table && table!=reinterpret_cast<FXAccelTable*>(-1)){
        table->removeAccel(acckey);
        }
      }
    }
  acckey=(FXHotKey)NULL;
  FXRbUnregisterRubyObj(this);
  }

//----------------------------------------------------------------------

// Visit all of the items between fm and to (inclusive), plus their
// child items, and add to the items list
void FXRbTreeList::enumerateItem(FXTreeItem* item,FXObjectListOf<FXTreeItem>& items){
  // Add this item to the list
  items.append(item);
  
  // Add this item's children
  FXRbTreeList::enumerateItems(item->getFirst(),item->getLast(),items);
  }


// Visit all of the items between fm and to (inclusive), plus their
// child items, and add to the items list
void FXRbTreeList::enumerateItems(FXTreeItem* fm,FXTreeItem* to,FXObjectListOf<FXTreeItem>& items){
  register FXTreeItem *item;
  if(fm && to){
    do{
      item=fm;
      fm=fm->getNext();
      FXRbTreeList::enumerateItem(item,items);
      }
    while(item!=to);
    }
  }

//----------------------------------------------------------------------

/**
 * Visit all of the items between fm and to (inclusive), plus their
 * child items, and add to the items list.
 */
void FXRbFoldingList::enumerateItem(FXFoldingItem* item,FXObjectListOf<FXFoldingItem>& items){
  // Add this item to the list
  items.append(item);
  
  // Add this item's children
  FXRbFoldingList::enumerateItems(item->getFirst(),item->getLast(),items);
  }


/**
 * Visit all of the items between fm and to (inclusive), plus their
 * child items, and add to the items list.
 */
void FXRbFoldingList::enumerateItems(FXFoldingItem* fm,FXFoldingItem* to,FXObjectListOf<FXFoldingItem>& items){
  register FXFoldingItem *item;
  if(fm && to){
    do{
      item=fm;
      fm=fm->getNext();
      FXRbFoldingList::enumerateItem(item,items);
      }
    while(item!=to);
    }
  }


//----------------------------------------------------------------------

static ID id_cmp;

// Sort function stand-in for FXComboBox
FXint FXRbComboBox::sortFunc(const FXListItem* a,const FXListItem* b){
  VALUE itemA = FXRbGetRubyObj(const_cast<FXListItem*>(a), "FXListItem *");
  VALUE itemB = FXRbGetRubyObj(const_cast<FXListItem*>(b), "FXListItem *");
  VALUE result=rb_funcall(itemA,id_cmp,1,itemB);
  return static_cast<FXint>(NUM2INT(result));
  }

  
// Sort function stand-in for FXFoldingList
FXint FXRbFoldingList::sortFunc(const FXFoldingItem* a,const FXFoldingItem* b){
  VALUE itemA = FXRbGetRubyObj(const_cast<FXFoldingItem*>(a), "FXFoldingItem *");
  VALUE itemB = FXRbGetRubyObj(const_cast<FXFoldingItem*>(b), "FXFoldingItem *");
  VALUE result=rb_funcall(itemA,id_cmp,1,itemB);
  return static_cast<FXint>(NUM2INT(result));
  }


// Sort function stand-in for FXIconList
FXint FXRbIconList::sortFunc(const FXIconItem* a,const FXIconItem* b){
  VALUE itemA = FXRbGetRubyObj(const_cast<FXIconItem*>(a), "FXIconItem *");
  VALUE itemB = FXRbGetRubyObj(const_cast<FXIconItem*>(b), "FXIconItem *");
  VALUE result = rb_funcall(itemA,id_cmp,1,itemB);
  return static_cast<FXint>(NUM2INT(result));
  }


// Sort function stand-in for FXList
FXint FXRbList::sortFunc(const FXListItem* a,const FXListItem* b){
  VALUE itemA = FXRbGetRubyObj(const_cast<FXListItem*>(a), "FXListItem *");
  VALUE itemB = FXRbGetRubyObj(const_cast<FXListItem*>(b), "FXListItem *");
  VALUE result=rb_funcall(itemA,id_cmp,1,itemB);
  return static_cast<FXint>(NUM2INT(result));
  }


// Sort function stand-in for FXListBox
FXint FXRbListBox::sortFunc(const FXListItem* a,const FXListItem* b){
  VALUE itemA = FXRbGetRubyObj(const_cast<FXListItem*>(a), "FXListItem *");
  VALUE itemB = FXRbGetRubyObj(const_cast<FXListItem*>(b), "FXListItem *");
  VALUE result=rb_funcall(itemA,id_cmp,1,itemB);
  return static_cast<FXint>(NUM2INT(result));
  }

  
// Sort function stand-in for FXTreeList
FXint FXRbTreeList::sortFunc(const FXTreeItem* a,const FXTreeItem* b){
  VALUE itemA = FXRbGetRubyObj(const_cast<FXTreeItem*>(a), "FXTreeItem *");
  VALUE itemB = FXRbGetRubyObj(const_cast<FXTreeItem*>(b), "FXTreeItem *");
  VALUE result=rb_funcall(itemA,id_cmp,1,itemB);
  return static_cast<FXint>(NUM2INT(result));
  }


// Feedback buffer sort routine stand-in for FXGLViewer
FXbool FXRbGLViewer::sortProc(FXfloat*& buffer,FXint& used,FXint& size){
  return TRUE;
  }

//----------------------------------------------------------------------

// Copied from the Ruby 1.8.6 sources (signal.c)
static struct signals {
    const char *signm;
    int  signo;
} siglist [] = {
    {"EXIT", 0},
#ifdef SIGHUP
#ifdef SIGQUIT
#endif
#ifdef SIGILL
#endif
#ifdef SIGTRAP
#endif
#ifdef SIGIOT
#endif
#ifdef SIGABRT
#endif
#ifdef SIGEMT
#endif
#ifdef SIGFPE
#endif
#ifdef SIGKILL
#endif
#ifdef SIGBUS
#endif
#ifdef SIGSEGV
#endif
#ifdef SIGSYS
#endif
#ifdef SIGPIPE
#endif
#ifdef SIGALRM
#endif
#ifdef SIGTERM
#endif
#ifdef SIGURG
#endif
#ifdef SIGSTOP
#endif
#ifdef SIGTSTP
#endif
#ifdef SIGCONT
#endif
#ifdef SIGCHLD
#endif
#ifdef SIGCLD
#else
# ifdef SIGCHLD
# endif
#endif
#ifdef SIGTTIN
#endif
#ifdef SIGTTOU
#endif
#ifdef SIGIO
#endif
#ifdef SIGXCPU
#endif
#ifdef SIGXFSZ
#endif
#ifdef SIGVTALRM
#endif
#ifdef SIGPROF
#endif
#ifdef SIGWINCH
#endif
#ifdef SIGUSR1
#endif
#ifdef SIGUSR2
#endif
#ifdef SIGLOST
#endif
#ifdef SIGMSG
#endif
#ifdef SIGPWR
#endif
#ifdef SIGPOLL
#endif
#ifdef SIGDANGER
#endif
#ifdef SIGMIGRATE
#endif
#ifdef SIGPRE
#endif
#ifdef SIGGRANT
#endif
#ifdef SIGRETRACT
#endif
#ifdef SIGSOUND
#endif
#ifdef SIGINFO
};

FXint FXRbSignalNameToNumber(const char* s){
#ifdef HAVE_SIGNAL_H
  const char *nm=s;
  if(strncmp("SIG",nm,3)==0){
    nm+=3;
    }
  for(signals* sigs=siglist;sigs->signm;sigs++){
    if(strcmp(sigs->signm,nm)==0)
      return sigs->signo;
    }
#endif /* HAVE_SIGNAL_H */
  return 0;
  }

//----------------------------------------------------------------------

/*
 * The Ruby header files define a TYPE(x) macro that conflicts with the
 * TYPE template parameter used in FXArray.h and FXElement.h.
 */
#ifdef TYPE
#undef TYPE
#endif

#include <new>

#include "FXArray.h"
#include "FXElement.h"

static st_table * appSensitiveObjs;
static st_table * appSensitiveDCs;

void FXRbRegisterAppSensitiveObject(FXObject* obj){
  FXASSERT(obj!=0);
  FXTRACE((100,"%s:%d: FXRbRegisterAppSensitiveObject(obj=%p(%s))\n",__FILE__,__LINE__,obj,obj->getClassName()));
  st_insert(appSensitiveObjs,reinterpret_cast<st_data_t>(obj),(st_data_t)0);
  FXASSERT(st_lookup(appSensitiveObjs,reinterpret_cast<st_data_t>(obj),reinterpret_cast<st_data_t *>(0))!=0);
  }

void FXRbRegisterAppSensitiveObject(FXDC* dc){
  FXASSERT(dc!=0);
  FXTRACE((100,"%s:%d: FXRbRegisterAppSensitiveObject(dc=%p)\n",__FILE__,__LINE__,dc));
  st_insert(appSensitiveDCs,reinterpret_cast<st_data_t>(dc),(st_data_t)0);
  FXASSERT(st_lookup(appSensitiveDCs,reinterpret_cast<st_data_t>(dc),reinterpret_cast<st_data_t *>(0))!=0);
  }

void FXRbUnregisterAppSensitiveObject(FXObject* obj){
  FXASSERT(obj!=0);
  FXTRACE((100,"%s:%d: FXRbUnregisterAppSensitiveObject(obj=%p(%s))\n",__FILE__,__LINE__,obj,obj->getClassName()));
  st_delete(appSensitiveObjs,reinterpret_cast<st_data_t *>(&obj),reinterpret_cast<st_data_t *>(0));
  FXASSERT(st_lookup(appSensitiveObjs,reinterpret_cast<st_data_t>(obj),reinterpret_cast<st_data_t *>(0))==0);
  }

void FXRbUnregisterAppSensitiveObject(FXDC* dc){
  FXASSERT(dc!=0);
  FXTRACE((100,"%s:%d: FXRbUnregisterAppSensitiveObject(dc=%p)\n",__FILE__,__LINE__,dc));
  st_delete(appSensitiveDCs,reinterpret_cast<st_data_t *>(&dc),reinterpret_cast<st_data_t *>(0));
  FXASSERT(st_lookup(appSensitiveDCs,reinterpret_cast<st_data_t>(dc),reinterpret_cast<st_data_t *>(0))==0);
  }

#ifdef ST_BROKEN_PROTOTYPES
static int st_cbfunc_obj(st_data_t key,st_data_t,st_data_t arg){
#else
static int st_cbfunc_obj(st_data_t key,st_data_t,st_data_t arg,int){
#endif
  FXASSERT(key!=0);
  FXASSERT(arg!=0);
  FXObjectListOf<FXObject> *pObjectList=reinterpret_cast<FXObjectListOf<FXObject>*>(arg);
  FXObject *pObject=reinterpret_cast<FXObject*>(key);
  pObjectList->append(pObject);
  return 0;
  }

#ifdef ST_BROKEN_PROTOTYPES
static int st_cbfunc_dc(st_data_t key,st_data_t,st_data_t arg){
#else
static int st_cbfunc_dc(st_data_t key,st_data_t,st_data_t arg,int){
#endif
  FXASSERT(key!=0);
  FXASSERT(arg!=0);
  FXArray<FXDC*> *pDCArray=reinterpret_cast<FXArray<FXDC*>*>(arg);
  FXDC *pDC=reinterpret_cast<FXDC*>(key);
  pDCArray->append(pDC);
  return 0;
  }

void FXRbDestroyAppSensitiveObjects(){
  FXTRACE((100,"%s:%d: Begin destroying objects that hold references to the FXApp...\n",__FILE__,__LINE__));

  FXObjectListOf<FXObject> objs;
#ifdef ST_BROKEN_PROTOTYPES
  st_foreach(appSensitiveObjs,st_cbfunc_obj,reinterpret_cast<st_data_t>(&objs));
#else
  st_foreach(appSensitiveObjs,reinterpret_cast<int (*)(ANYARGS)>(st_cbfunc_obj),reinterpret_cast<st_data_t>(&objs));
#endif
  for(FXint i=0;i<objs.no();i++){
    if(objs[i]->isMemberOf(FXMETACLASS(FXRbCursor))){
      if(dynamic_cast<FXRbCursor*>(objs[i])->ownedByApp)
	continue;
      }
    else if(objs[i]->isMemberOf(FXMETACLASS(FXRbCURCursor))){
      if(dynamic_cast<FXRbCURCursor*>(objs[i])->ownedByApp)
	continue;
      }
    else if(objs[i]->isMemberOf(FXMETACLASS(FXRbGIFCursor))){
      if(dynamic_cast<FXRbGIFCursor*>(objs[i])->ownedByApp)
	continue;
      }
    else if(objs[i]->isMemberOf(FXMETACLASS(FXRbFont))){
      if(dynamic_cast<FXRbFont*>(objs[i])->ownedByApp)
	continue;
      }
    else if(objs[i]->isMemberOf(FXMETACLASS(FXRbGLVisual))){
      if(dynamic_cast<FXRbGLVisual*>(objs[i])->ownedByApp)
	continue;
      }
    else if(objs[i]->isMemberOf(FXMETACLASS(FXRbVisual))){
      if(dynamic_cast<FXRbVisual*>(objs[i])->ownedByApp)
	continue;
      }
    delete objs[i];
    }

  FXArray<FXDC*> dcs;
#ifdef ST_BROKEN_PROTOTYPES
  st_foreach(appSensitiveDCs,st_cbfunc_dc,reinterpret_cast<st_data_t>(&dcs));
#else
  st_foreach(appSensitiveDCs,reinterpret_cast<int (*)(ANYARGS)>(st_cbfunc_dc),reinterpret_cast<st_data_t>(&dcs));
#endif
  for(FXint j=0;j<dcs.no();j++){
    delete dcs[j];
    }

  FXTRACE((100,"%s:%d: Finished destroying objects that hold references to the FXApp.\n",__FILE__,__LINE__));
  }

//----------------------------------------------------------------------

extern "C" void Init_core(void);
extern "C" void Init_dc(void);
extern "C" void Init_dialogs(void);
extern "C" void Init_frames(void);
extern "C" void Init_fx3d(void);
extern "C" void Init_image(void);
extern "C" void Init_iconlist(void);
extern "C" void Init_icons(void);
extern "C" void Init_label(void);