Skip to content
Snippets Groups Projects
FXRuby.cpp 62 KiB
Newer Older
  • Learn to ignore specific revisions
  • /***********************************************************************
     * FXRuby -- the Ruby language bindings for the FOX GUI toolkit.
    
     * Copyright (c) 2001-2009 by Lyle Johnson. All Rights Reserved.
    
     *
     * This library is free software; you can redistribute it and/or
     * modify it under the terms of the GNU Lesser General Public
     * License as published by the Free Software Foundation; either
     * version 2.1 of the License, or (at your option) any later version.
     *
     * This library is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     * Lesser General Public License for more details.
     *
     * You should have received a copy of the GNU Lesser General Public
     * License along with this library; if not, write to the Free Software
     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     *
     * For further information please contact the author by e-mail
    
     * at "lyle@lylejohnson.name".
    
     ***********************************************************************/
    
    /***********************************************************************
    
     * $Id: FXRuby.cpp 2933 2008-12-29 20:19:33Z lyle $
    
     ***********************************************************************/
    
    #ifdef _MSC_VER
    #pragma warning (disable : 4786)
    #endif
    
    #include "FXRbCommon.h"
    #include "impl.h"
    
    #ifdef __CYGWIN__
    #include <io.h>		// for get_osf_handle()
    #endif
    
    #ifdef HAVE_SIGNAL_H
    #include <signal.h>	// for definitions of SIGINT, etc.
    #endif
    
    
    #include "ruby/io.h"
    
    extern "C" {
    #include "st.h"
    
    #include "rubyio.h"     // for GetOpenFile(), etc.
    
    // Opaque type declaration from SWIG runtime
    struct swig_type_info;
    
    // Wrapper around SWIG_TypeQuery() that caches results for performance
    swig_type_info *FXRbTypeQuery(const char *desc){
      FXASSERT(desc!=0);
      static st_table *types=st_init_strtable();
      swig_type_info *typeinfo=0;
      if(st_lookup(types,reinterpret_cast<st_data_t>(const_cast<char*>(desc)),reinterpret_cast<st_data_t *>(&typeinfo))==0){
        typeinfo=SWIG_Ruby_TypeQuery(desc);
        st_insert(types,reinterpret_cast<st_data_t>(strdup(desc)),reinterpret_cast<st_data_t>(typeinfo));
        }
      FXASSERT(typeinfo!=0);
      return typeinfo;
      }
    
    
    /**
     * The FXRuby_Objects hash table basically maps C++ objects to Ruby instances.
     * Each key in the table is a pointer to a C++ object we've seen before, and
     * the corresponding value is an FXRubyObjDesc struct (see below) that tells
     * us which Ruby instance corresponds to that C++ object.
     */
    
    static st_table * FXRuby_Objects;
    
    /**
     * Each value in the FXRuby_Objects hash table is an instance of this
     * struct. It identifies the Ruby instance associated with a C++ object.
     * It also indicates whether this is merely a "borrowed" reference to
     * some C++ object (i.e. it's not one we need to destroy later).
     */
    
    struct FXRubyObjDesc {
      VALUE obj;
      bool borrowed;
      };
    
    
    /**
     * FXRbNewPointerObj() is a wrapper around SWIG_Ruby_NewPointerObj() that also
     * registers this C++ object & Ruby instance pair in our FXRuby_Objects
     * hash table. This function should only get called for methods that return
     * a reference to an already-existing C++ object (i.e. one that FOX "owns")
     * and for that reason we mark these objects as "borrowed".
     */
    
    VALUE FXRbNewPointerObj(void *ptr,swig_type_info* ty){
      if(ptr!=0){
        FXASSERT(ty!=0);
        VALUE obj;
        FXRubyObjDesc *desc;
        if(FXMALLOC(&desc,FXRubyObjDesc,1)){
          obj=SWIG_Ruby_NewPointerObj(ptr,ty,1);
          desc->obj=obj;
          desc->borrowed=true;
    
          st_insert(FXRuby_Objects,reinterpret_cast<st_data_t>(ptr),reinterpret_cast<st_data_t>(desc));
    
          return obj;
          }
        else{
          FXASSERT(FALSE);
          return Qnil;
          }
        }
      else{
        return Qnil;
        }
      }
    
    
    /**
     * FXRbIsBorrowed() returns true if the specified C++ object is one that
     * FOX owns (i.e. it's borrowed).
     */
    
    bool FXRbIsBorrowed(void* ptr){
      FXASSERT(ptr!=0);
      FXRubyObjDesc *desc;
      if(st_lookup(FXRuby_Objects,reinterpret_cast<st_data_t>(ptr),reinterpret_cast<st_data_t *>(&desc))!=0){
        return desc->borrowed;
        }
      else{
        return true;
        }
      }
    
    
    /**
     * FXRbConvertPtr() is just a wrapper around SWIG_Ruby_ConvertPtr().
     */
    
    void* FXRbConvertPtr(VALUE obj,swig_type_info* ty){
      void *ptr;
      SWIG_Ruby_ConvertPtr(obj,&ptr,ty,1);
      return ptr;
      }
    
    
    // Should we catch exceptions thrown by message handlers?
    FXbool FXRbCatchExceptions=FALSE;
    
    // Returns an FXInputHandle for this Ruby file object
    FXInputHandle FXRbGetReadFileHandle(VALUE obj) {
    
      int fd;
      fd = FIX2INT(rb_funcall(obj, rb_intern("fileno"), 0));
    
    #ifdef WIN32
    #ifdef __CYGWIN__
    
      return (FXInputHandle) get_osfhandle(fd);
    
      return (FXInputHandle) _get_osfhandle(fd);
    
    #endif
      }
    
    
    // Returns an FXInputHandle for this Ruby file object
    FXInputHandle FXRbGetWriteFileHandle(VALUE obj) {
    
    #if defined(RUBINIUS)
      VALUE vwrite = rb_intern("@write");
      if(rb_ivar_defined(obj, vwrite)) obj = rb_ivar_get(obj, vwrite);
    
      fd = FIX2INT(rb_funcall(obj, rb_intern("fileno"), 0));
    
    #elif defined(RUBY_1_9)
    
      rb_io_t *fptr;
      GetOpenFile(obj, fptr);
    
      VALUE wrio = fptr->tied_io_for_writing;
      if(wrio) obj = wrio;
    
      fd = FIX2INT(rb_funcall(obj, rb_intern("fileno"), 0));
    
      OpenFile *fptr;
      GetOpenFile(obj, fptr);
      FILE *fpw=GetWriteFile(fptr);
    
    #ifdef WIN32
    #ifdef __CYGWIN__
    
      return (FXInputHandle) get_osfhandle(fd);
    
      return (FXInputHandle) _get_osfhandle(fd);
    
    #endif
      }
    
    
    // Register this Ruby class instance
    void FXRbRegisterRubyObj(VALUE rubyObj,const void* foxObj) {
      FXASSERT(!NIL_P(rubyObj));
      FXASSERT(foxObj!=0);
      FXRubyObjDesc* desc;
    
      FXTRACE((1,"FXRbRegisterRubyObj(rubyObj=%d,foxObj=%p)\n",static_cast<int>(rubyObj),foxObj));
    
      if(FXMALLOC(&desc,FXRubyObjDesc,1)){
        desc->obj=rubyObj;
        desc->borrowed=false;
        st_insert(FXRuby_Objects,reinterpret_cast<st_data_t>(const_cast<void*>(foxObj)),reinterpret_cast<st_data_t>(desc));
        }
      else{
        FXASSERT(FALSE);
        }
      FXASSERT(FXRbGetRubyObj(foxObj,false)==rubyObj);
      }
    
    
    /**
     * Remove this mapping between a Ruby instance and a C++ object
     */
    void FXRbUnregisterRubyObj(const void* foxObj){
      if(foxObj!=0){
        FXRubyObjDesc* desc;
        if(st_lookup(FXRuby_Objects,reinterpret_cast<st_data_t>(const_cast<void*>(foxObj)),reinterpret_cast<st_data_t *>(&desc))!=0){
          DATA_PTR(desc->obj)=0;
          FXFREE(&desc);
          st_delete(FXRuby_Objects,reinterpret_cast<st_data_t *>(const_cast<void**>(&foxObj)),reinterpret_cast<st_data_t *>(0));
          FXASSERT(st_lookup(FXRuby_Objects,reinterpret_cast<st_data_t>(const_cast<void*>(foxObj)),reinterpret_cast<st_data_t *>(0))==0);
          }
        }
      }
    
    
    VALUE to_ruby(const FXObject* obj){
      if(obj!=0){
        FXString className=obj->getClassName();
        if(className.length()>3){
          if(className.left(4)=="FXRb"){ className.replace(0,4,"FX"); }
          }
        FXString desc=className+" *";
        return FXRbGetRubyObj(obj,desc.text());
        }
      return Qnil;
      }
    
    
    /**
     * Return the registered Ruby class instance associated with this
     * FOX object, or Qnil if not found.
     */
    VALUE FXRbGetRubyObj(const void *foxObj,bool searchBoth){
      FXRubyObjDesc* desc;
      if(foxObj!=0 && st_lookup(FXRuby_Objects,reinterpret_cast<st_data_t>(const_cast<void*>(foxObj)),reinterpret_cast<st_data_t *>(&desc))!=0){
        FXASSERT(desc!=0);
        if(searchBoth){
          return desc->obj;
          }
        else{
          return desc->borrowed ? Qnil : desc->obj;
          }
        }
      else{
        return Qnil;
        }
      }
    
    /**
     * Return the registered Ruby class instance associated with this
     * FOX object, or a new registered instance if not found.
     */
    VALUE FXRbGetRubyObj(const void *foxObj,swig_type_info* ty){
      if(foxObj!=0){
        VALUE rbObj=FXRbGetRubyObj(foxObj,true);
        return NIL_P(rbObj) ? FXRbNewPointerObj(const_cast<void*>(foxObj),ty) : rbObj;
        }
      else{
        return Qnil;
        }
      }
    
    VALUE FXRbGetRubyObj(const void *foxObj,const char *type){
      if(foxObj!=0){
        FXASSERT(type!=0);
        VALUE rbObj=FXRbGetRubyObj(foxObj,true);
        return NIL_P(rbObj) ? FXRbNewPointerObj(const_cast<void*>(foxObj),FXRbTypeQuery(type)) : rbObj;
        }
      else{
        return Qnil;
        }
      }
    
    /**
     * Look up the Ruby instance associated with this C++ object, if any, and mark
     * that instance as in use.
     *
     * We previously only marked those Ruby instances that were "non-borrowed"
     * references to C++ objects, as a way to reduce the number of Ruby instances
     * on the heap.
     */
    void FXRbGcMark(void *obj){
      if(obj){
        /**
         * If the 2nd argument to FXRbGetRubyObj() is false, we only mark
         * non-borrowed references. This has led to problems in the past
         * (see e.g. SourceForge Bug #703721). I think the correct solution
         * is to mark any Ruby reference this object, "borrowed" or not;
         * so the 2nd argument to FXRbGetRubyObj() is now true.
         *
         * If you feel compelled to change this back to FXGetRubyObj(obj,false),
         * please think about it first. Especially make sure that the shutter.rb
         * example program works if you invoke the GC in ShutterWindow#create;
         * make sure that the shutter items' contents don't get blown away!
         */
        VALUE value=FXRbGetRubyObj(obj,true);
        if(!NIL_P(value)){
          rb_gc_mark(value);
          }
        }
      }
    
    //----------------------------------------------------------------------
    
    // Returns a Ruby array of floats
    VALUE FXRbMakeArray(const FXfloat* values,FXint size){
      VALUE result=rb_ary_new();
      for(FXint i=0; i<size; i++)
        rb_ary_push(result,rb_float_new(values[i]));
      return result;
      }
    
    // Returns a Ruby array of floats
    VALUE FXRbMakeArray(const FXdouble* values,FXint size){
      VALUE result=rb_ary_new();
      for(FXint i=0; i<size; i++)
        rb_ary_push(result,rb_float_new(values[i]));
      return result;
      }
    
    // Returns a Ruby array of integers
    VALUE FXRbMakeArray(const FXint* values,FXint size){
      VALUE result=rb_ary_new();
      for(FXint i=0; i<size; i++)
        rb_ary_push(result,INT2NUM(values[i]));
      return result;
      }
    
    // Returns a Ruby array of integers
    VALUE FXRbMakeArray(const FXuint* values,FXint size){
      VALUE result=rb_ary_new();
      for(FXint i=0; i<size; i++)
        rb_ary_push(result,UINT2NUM(values[i]));
      return result;
      }
    
    // Returns a Ruby array of integers
    VALUE FXRbMakeArray(const FXchar* dashpattern,FXuint dashlength){
      VALUE result=rb_ary_new();
      for(FXuint i=0; i<dashlength; i++)
        rb_ary_push(result,INT2NUM(dashpattern[i]));
      return result;
      }
    
    // Returns a Ruby array of FXArcs
    VALUE FXRbMakeArray(const FXArc* arcs,FXuint narcs){
      VALUE result=rb_ary_new();
      for(FXuint i=0; i<narcs; i++)
        rb_ary_push(result,FXRbGetRubyObj(&arcs[i],"FXArc *"));
      return result;
      }
    
    // Returns a Ruby array of FXPoints
    VALUE FXRbMakeArray(const FXPoint* points,FXuint npoints){
      VALUE result=rb_ary_new();
      for(FXuint i=0; i<npoints; i++)
        rb_ary_push(result,FXRbGetRubyObj(&points[i],"FXPoint *"));
      return result;
      }
    
    // Returns a Ruby array of FXRectangles
    VALUE FXRbMakeArray(const FXRectangle* rectangles,FXuint nrectangles){
      VALUE result=rb_ary_new();
      for(FXuint i=0; i<nrectangles; i++)
        rb_ary_push(result,FXRbGetRubyObj(&rectangles[i],"FXRectangle *"));
      return result;
      }
    
    // Returns a Ruby array of FXSegments
    VALUE FXRbMakeArray(const FXSegment* segments,FXuint nsegments){
      VALUE result=rb_ary_new();
      for(FXuint i=0; i<nsegments; i++)
        rb_ary_push(result,FXRbGetRubyObj(&segments[i],"FXSegment *"));
      return result;
      }
    
    // Returns a Ruby array of FXColor values
    VALUE FXRbMakeColorArray(const FXColor* colors,FXint w,FXint h){
      VALUE result=rb_ary_new();
      FXint size=w*h;
      for(FXuint i=0; i<size; i++)
        rb_ary_push(result,to_ruby(colors[i]));
      return result;
      }
    
    //----------------------------------------------------------------------
    
    /**
     * Based on the sender object's class and the selector, convert the message
     * data stored in the void pointer (ptr) to a suitable Ruby object.
     *
     * This function is used when we need to pass message data into a Ruby
     * code block (or method) that is acting as a FOX message handler.
     */
    static VALUE FXRbConvertMessageData(FXObject* sender,FXObject* recv,FXSelector sel,void* ptr){
      FXTRACE((1,"FXRbConvertMessageData(%s(%p),FXSEL(%s,%d),%p)\n",sender->getClassName(),sender,FXDebugTarget::messageTypeName[FXSELTYPE(sel)],FXSELID(sel),ptr));
      FXInputHandle fff;
      FXushort type=FXSELTYPE(sel);
      FXushort id=FXSELID(sel);
    
      FXASSERT(type!=SEL_NONE);
      FXASSERT(type!=SEL_LAST);
    
      if(type==SEL_KEYPRESS ||
         type==SEL_KEYRELEASE ||
         type==SEL_LEFTBUTTONPRESS ||
         type==SEL_LEFTBUTTONRELEASE ||
         type==SEL_MIDDLEBUTTONPRESS ||
         type==SEL_MIDDLEBUTTONRELEASE ||
         type==SEL_RIGHTBUTTONPRESS ||
         type==SEL_RIGHTBUTTONRELEASE ||
         type==SEL_MOTION ||
         type==SEL_ENTER ||
         type==SEL_LEAVE ||
         type==SEL_FOCUSIN ||
         type==SEL_FOCUSOUT ||
         type==SEL_KEYMAP ||
         type==SEL_UNGRABBED ||
         type==SEL_PAINT ||
         type==SEL_CREATE ||
         type==SEL_DESTROY ||
         type==SEL_UNMAP ||
         type==SEL_MAP ||
         type==SEL_CONFIGURE ||
         type==SEL_SELECTION_LOST ||
         type==SEL_SELECTION_GAINED ||
         type==SEL_SELECTION_REQUEST ||
         type==SEL_RAISED ||
         type==SEL_LOWERED ||
         type==SEL_MOUSEWHEEL ||
         type==SEL_BEGINDRAG ||
         type==SEL_ENDDRAG ||
         type==SEL_TIMEOUT ||
         type==SEL_CLIPBOARD_LOST ||
         type==SEL_CLIPBOARD_GAINED ||
         type==SEL_CLIPBOARD_REQUEST ||
         type==SEL_CHORE ||
         type==SEL_FOCUS_SELF ||
         type==SEL_FOCUS_RIGHT ||
         type==SEL_FOCUS_LEFT ||
         type==SEL_FOCUS_DOWN ||
         type==SEL_FOCUS_UP ||
         type==SEL_FOCUS_NEXT ||
         type==SEL_FOCUS_PREV ||
         type==SEL_DND_ENTER ||
         type==SEL_DND_LEAVE ||
         type==SEL_DND_DROP ||
         type==SEL_DND_MOTION ||
         type==SEL_DND_REQUEST ||
         type==SEL_PICKED ||
         type==SEL_SESSION_NOTIFY ||
         type==SEL_SESSION_CLOSED) {
        return to_ruby(reinterpret_cast<FXEvent*>(ptr));
        }
      else if(type==SEL_DRAGGED && !sender->isMemberOf(FXMETACLASS(FXGLViewer))){
        return to_ruby(reinterpret_cast<FXEvent*>(ptr));
        }
      else if(type==SEL_SIGNAL){
        return to_ruby(static_cast<int>(reinterpret_cast<long>(ptr)));
        }
      else if(type==SEL_IO_READ ||
              type==SEL_IO_WRITE ||
    	  type==SEL_IO_EXCEPT){
    #ifdef WIN32
        fff=reinterpret_cast<FXInputHandle>(ptr);
    #else
        fff=static_cast<FXInputHandle>(reinterpret_cast<long>(ptr));
    #endif
        return Qnil;
        }
      else if(type==SEL_CLOSE ||
              type==SEL_DELETE ||
              type==SEL_MINIMIZE ||
              type==SEL_RESTORE ||
              type==SEL_MAXIMIZE ||
              type==SEL_UPDATE ||
              type==SEL_QUERY_HELP ||
    	  type==SEL_QUERY_TIP){
        FXASSERT(ptr==0);
        return Qnil;
        }
      else if(sender->isMemberOf(FXMETACLASS(FX4Splitter))){
        if(type==SEL_CHANGED||type==SEL_COMMAND) return Qnil;
        }
      else if(sender->isMemberOf(FXMETACLASS(FXArrowButton))){
        if(type==SEL_COMMAND) return to_ruby(static_cast<FXuint>(reinterpret_cast<FXuval>(ptr)));
        }
    
      else if(sender->isMemberOf(FXMETACLASS(FXPicker))){
        if(type==SEL_COMMAND || type==SEL_CHANGED) return to_ruby(reinterpret_cast<FXPoint*>(ptr));
        }
    
      else if(sender->isMemberOf(FXMETACLASS(FXButton))){
        if(type==SEL_CLICKED ||
           type==SEL_DOUBLECLICKED ||
           type==SEL_TRIPLECLICKED ||
           type==SEL_COMMAND) return to_ruby(static_cast<FXuint>(reinterpret_cast<FXuval>(ptr)));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXCheckButton))){
        if(type==SEL_COMMAND) return to_ruby(static_cast<FXuchar>(reinterpret_cast<FXuval>(ptr)));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXColorBar))){
        if(type==SEL_CHANGED || type==SEL_COMMAND){
          FXfloat* hsv=reinterpret_cast<FXfloat*>(ptr);
          return rb_ary_new3(3,to_ruby(hsv[0]),to_ruby(hsv[1]),to_ruby(hsv[2]));
          }
        }
      else if(sender->isMemberOf(FXMETACLASS(FXColorDialog))){
        if(type==SEL_CHANGED || type==SEL_COMMAND) return to_ruby(static_cast<FXColor>(reinterpret_cast<unsigned long>(ptr)));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXColorRing))){
        if(type==SEL_CHANGED || type==SEL_COMMAND){
          FXfloat* hsv=reinterpret_cast<FXfloat*>(ptr);
          return rb_ary_new3(3,to_ruby(hsv[0]),to_ruby(hsv[1]),to_ruby(hsv[2]));
          }
        }
      else if(sender->isMemberOf(FXMETACLASS(FXColorSelector))){
        if(type==SEL_CHANGED || type==SEL_COMMAND) return to_ruby(static_cast<FXColor>(reinterpret_cast<unsigned long>(ptr)));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXColorWell))){
        if(type==SEL_CHANGED ||
           type==SEL_COMMAND ||
           type==SEL_CLICKED ||
           type==SEL_DOUBLECLICKED ||
           type==SEL_TRIPLECLICKED) {
    	       VALUE v=to_ruby(static_cast<FXColor>(reinterpret_cast<unsigned long>(ptr)));
    	       return v;
        }
        }
      else if(sender->isMemberOf(FXMETACLASS(FXColorWheel))){
        if(type==SEL_CHANGED || type==SEL_COMMAND){
          FXfloat* hsv=reinterpret_cast<FXfloat*>(ptr);
          return rb_ary_new3(3,to_ruby(hsv[0]),to_ruby(hsv[1]),to_ruby(hsv[2]));
          }
        }
      else if(sender->isMemberOf(FXMETACLASS(FXComboBox))){
        if(type==SEL_CHANGED || type==SEL_COMMAND) return to_ruby(reinterpret_cast<FXchar*>(ptr));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXDataTarget))){
        if(type==SEL_COMMAND || type==SEL_CHANGED){
          if(recv->isMemberOf(FXMETACLASS(FXWindow))){
            switch(id){
              case FXWindow::ID_SETINTVALUE:
                return to_ruby(*reinterpret_cast<FXint*>(ptr));
              case FXWindow::ID_SETREALVALUE:
                return to_ruby(*reinterpret_cast<FXdouble*>(ptr));
              case FXWindow::ID_SETSTRINGVALUE:
                return to_ruby(*reinterpret_cast<FXString*>(ptr));
              case FXWindow::ID_GETINTVALUE:
              case FXWindow::ID_GETREALVALUE:
              case FXWindow::ID_GETSTRINGVALUE:
                FXASSERT(FALSE);
                break;
              default:
                FXASSERT(FALSE);
              }
            }
          else{
            // It's not a window object...
            FXASSERT(sender->isMemberOf(FXMETACLASS(FXRbDataTarget)));
            return dynamic_cast<FXRbDataTarget*>(sender)->getValue();
            }
          }
        }
      else if(sender->isMemberOf(FXMETACLASS(FXDial))){
        if(type==SEL_CHANGED || type==SEL_COMMAND) return to_ruby(static_cast<FXint>(reinterpret_cast<FXival>(ptr)));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXDirBox))){
        if(type==SEL_CHANGED || type==SEL_COMMAND) return to_ruby(reinterpret_cast<FXchar*>(ptr));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXDockBar))){
        if(type==SEL_DOCKED || type==SEL_FLOATED) return FXRbGetRubyObj(ptr,FXRbTypeQuery("FXDockSite *"));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXFileList))){
        if (type==SEL_CHANGED ||
            type==SEL_CLICKED ||
            type==SEL_DOUBLECLICKED ||
            type==SEL_TRIPLECLICKED ||
            type==SEL_COMMAND) return to_ruby(static_cast<FXint>(reinterpret_cast<FXival>(ptr)));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXFoldingList))){
        if(type==SEL_COLLAPSED ||
           type==SEL_EXPANDED ||
           type==SEL_COMMAND ||
           type==SEL_CHANGED ||
           type==SEL_CLICKED ||
           type==SEL_DOUBLECLICKED ||
           type==SEL_TRIPLECLICKED ||
           type==SEL_OPENED ||
           type==SEL_CLOSED ||
           type==SEL_SELECTED ||
           type==SEL_DESELECTED ||
           type==SEL_INSERTED ||
           type==SEL_DELETED){
          return FXRbGetRubyObj(ptr,FXRbTypeQuery("FXFoldingItem *"));
          }
        }
      else if(sender->isMemberOf(FXMETACLASS(FXGLViewer))){
        if(type==SEL_CHANGED ||
           type==SEL_CLICKED ||
           type==SEL_DOUBLECLICKED ||
           type==SEL_TRIPLECLICKED ||
           type==SEL_DRAGGED){
          return FXRbGetRubyObj(ptr,FXRbTypeQuery("FXGLObject *"));
          }
        else if(type==SEL_COMMAND){
          if(id==FXWindow::ID_QUERY_MENU)
            return to_ruby(reinterpret_cast<FXEvent*>(ptr));
          else
            return FXRbGetRubyObj(ptr,FXRbTypeQuery("FXGLObject *"));
          }
        else if(type==SEL_LASSOED ||
                type==SEL_INSERTED ||
                type==SEL_DELETED ||
                type==SEL_SELECTED ||
                type==SEL_DESELECTED){
          VALUE ary=rb_ary_new();
    
          // FXGLObject** objlist=reinterpret_cast<FXGLObject**>(ptr);
    
          // FIXME: objlist is a NULL-terminated array of pointers to FXGLObject
          return ary;
          }
        }
      else if(sender->isMemberOf(FXMETACLASS(FXGradientBar))){
        if(type==SEL_CHANGED){
          return to_ruby(static_cast<FXint>(reinterpret_cast<FXival>(ptr)));
          }
        else if(type==SEL_SELECTED || type==SEL_DESELECTED){
          return Qnil;
          }
        }
      else if(sender->isMemberOf(FXMETACLASS(FXHeader))){
        if(type==SEL_COMMAND ||
           type==SEL_CHANGED ||
           type==SEL_CLICKED ||
           type==SEL_REPLACED ||
           type==SEL_INSERTED ||
           type==SEL_DELETED) return to_ruby(static_cast<FXint>(reinterpret_cast<FXival>(ptr)));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXIconList))){
        if(type==SEL_CHANGED ||
           type==SEL_CLICKED ||
           type==SEL_DOUBLECLICKED ||
           type==SEL_TRIPLECLICKED ||
           type==SEL_COMMAND ||
           type==SEL_SELECTED ||
           type==SEL_DESELECTED ||
           type==SEL_REPLACED ||
           type==SEL_INSERTED ||
           type==SEL_DELETED) return to_ruby(static_cast<FXint>(reinterpret_cast<FXival>(ptr)));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXKnob))){
        if(type==SEL_CHANGED || type==SEL_COMMAND) return to_ruby(static_cast<FXint>(reinterpret_cast<FXival>(ptr)));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXList))){
        if(type==SEL_CHANGED ||
           type==SEL_CLICKED ||
           type==SEL_DOUBLECLICKED ||
           type==SEL_TRIPLECLICKED ||
           type==SEL_SELECTED ||
           type==SEL_DESELECTED ||
           type==SEL_REPLACED ||
           type==SEL_INSERTED ||
           type==SEL_DELETED ||
           type==SEL_COMMAND) return to_ruby(static_cast<FXint>(reinterpret_cast<FXival>(ptr)));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXListBox))){
        if(type==SEL_COMMAND) return to_ruby(static_cast<FXint>(reinterpret_cast<FXival>(ptr)));
        else if(type==SEL_CHANGED) return Qnil;
        }
      else if(sender->isMemberOf(FXMETACLASS(FXMDIChild))){
        if(type==SEL_MINIMIZE ||
           type==SEL_MAXIMIZE ||
           type==SEL_CLOSE ||
           type==SEL_RESTORE){
           return Qnil;
          }
        else if(type==SEL_SELECTED ||
                type==SEL_DESELECTED){
          return FXRbGetRubyObj(ptr,FXRbTypeQuery("FXMDIChild *"));
          }
        }
      else if(sender->isMemberOf(FXMETACLASS(FXMDIClient))){
        if(type==SEL_CHANGED) return FXRbGetRubyObj(ptr,FXRbTypeQuery("FXMDIChild *"));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXMenuCheck))){
        if(type==SEL_COMMAND) return to_ruby(reinterpret_cast<FXuval>(ptr));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXMenuRadio))){
        if(type==SEL_COMMAND) return to_ruby(reinterpret_cast<FXuval>(ptr));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXMenuCommand))){
        if(type==SEL_COMMAND) return to_ruby(true);
        }
      else if(sender->isMemberOf(FXMETACLASS(FXOption))){
        if(type==SEL_COMMAND) return to_ruby(reinterpret_cast<FXEvent*>(ptr));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXOptionMenu))){
        if(type==SEL_COMMAND) return to_ruby(static_cast<FXint>(reinterpret_cast<FXival>(ptr)));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXRadioButton))){
        if(type==SEL_COMMAND) return to_ruby(static_cast<FXuchar>(reinterpret_cast<FXuval>(ptr)));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXRealSlider))){
        if(type==SEL_CHANGED || type==SEL_COMMAND)
          return to_ruby(*(reinterpret_cast<FXdouble *>(ptr)));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXRealSpinner))){
        if(type==SEL_COMMAND || type==SEL_CHANGED) return to_ruby(*(reinterpret_cast<FXdouble *>(ptr)));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXRecentFiles))){
        if(type==SEL_COMMAND) return to_ruby(reinterpret_cast<FXchar*>(ptr));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXRuler))){
        if(type==SEL_CHANGED) return Qnil;
        }
      else if(sender->isMemberOf(FXMETACLASS(FXScrollBar))){
        if(type==SEL_CHANGED || type==SEL_COMMAND) return to_ruby(static_cast<FXint>(reinterpret_cast<FXival>(ptr)));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXShutter))){
        if(type==SEL_COMMAND) return to_ruby(static_cast<FXint>(reinterpret_cast<FXival>(ptr)));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXSlider))){
        if(type==SEL_CHANGED || type==SEL_COMMAND)
          return to_ruby(static_cast<FXint>(reinterpret_cast<FXival>(ptr)));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXSpinner))){
        if(type==SEL_CHANGED || type==SEL_COMMAND)
          return to_ruby(static_cast<FXint>(reinterpret_cast<long>(ptr)));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXSplitter))){
        if(type==SEL_CHANGED || type==SEL_COMMAND)
          return to_ruby(reinterpret_cast<FXWindow *>(ptr));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXSwitcher))){
        if(type==SEL_COMMAND) return to_ruby(static_cast<FXint>(reinterpret_cast<FXival>(ptr)));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXTabBar))){
        if(type==SEL_COMMAND) return to_ruby(static_cast<FXint>(reinterpret_cast<FXival>(ptr)));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXTable))){
        if(type==SEL_CLICKED ||
           type==SEL_DOUBLECLICKED ||
           type==SEL_TRIPLECLICKED ||
           type==SEL_CHANGED ||
           type==SEL_COMMAND ||
           type==SEL_SELECTED ||
           type == SEL_DESELECTED) return to_ruby(reinterpret_cast<FXTablePos*>(ptr));
        else if(type == SEL_INSERTED ||
                type == SEL_DELETED ||
                type == SEL_REPLACED){
    	      return to_ruby(reinterpret_cast<FXTableRange*>(ptr));
    	      }
        }
      else if(sender->isMemberOf(FXMETACLASS(FXText))){
        if     (type == SEL_COMMAND) {
          switch(id){
            case FXText::ID_COPY_SEL:
            case FXText::ID_PASTE_SEL:
            case FXText::ID_DELETE_SEL:
              return Qnil;
              break;
            default:
              FXASSERT(FALSE);
              return reinterpret_cast<VALUE>(ptr); // pass-through as is
            }
          }
        else if(type==SEL_CHANGED){
          return to_ruby(static_cast<FXint>(reinterpret_cast<FXival>(ptr)));
          }
        else if(type==SEL_SELECTED ||
                type == SEL_DESELECTED) {
          FXint* what=reinterpret_cast<FXint*>(ptr);
          FXASSERT(what!=0);
          VALUE ary=rb_ary_new();
          rb_ary_push(ary,to_ruby(what[0])); // start position of text
          rb_ary_push(ary,to_ruby(what[1])); // length of text
          return ary;
          }
        else if(type==SEL_INSERTED || type==SEL_DELETED || type==SEL_REPLACED) {
          return to_ruby(reinterpret_cast<FXTextChange*>(ptr));
          }
        }
      else if(sender->isMemberOf(FXMETACLASS(FXTextField))){
        if(type==SEL_CHANGED ||
           type==SEL_COMMAND ||
           type==SEL_VERIFY) return to_ruby(reinterpret_cast<FXchar*>(ptr));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXToggleButton))){
        if(type==SEL_COMMAND) return to_ruby(static_cast<FXuchar>(reinterpret_cast<FXuval>(ptr)));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXToolBarTab))){
        if (type==SEL_COMMAND) return to_ruby(static_cast<FXbool>(reinterpret_cast<FXuval>(ptr)));
        }
      else if(sender->isMemberOf(FXMETACLASS(FXTopWindow))){
        if(type==SEL_MINIMIZE ||
           type==SEL_MAXIMIZE ||
           type==SEL_RESTORE ||
           type==SEL_CLOSE){
          return Qnil;
          }
        else if (type==SEL_SESSION_NOTIFY ||
                 type==SEL_SESSION_CLOSED) {
          return to_ruby(reinterpret_cast<FXEvent*>(ptr));
          }
        }
      else if(sender->isMemberOf(FXMETACLASS(FXTreeList))){
        if(type==SEL_COLLAPSED ||
           type==SEL_EXPANDED ||
           type==SEL_COMMAND ||
           type==SEL_CHANGED ||
           type==SEL_CLICKED ||
           type==SEL_DOUBLECLICKED ||
           type==SEL_TRIPLECLICKED ||
           type==SEL_OPENED ||
           type==SEL_CLOSED ||
           type==SEL_SELECTED ||
           type==SEL_DESELECTED ||
           type==SEL_INSERTED ||
           type==SEL_DELETED){
          return FXRbGetRubyObj(ptr,FXRbTypeQuery("FXTreeItem *"));
          }
        }
      else if(sender->isMemberOf(FXMETACLASS(FXTreeListBox))){
        if(type==SEL_CHANGED || type==SEL_COMMAND)
          return FXRbGetRubyObj(ptr,FXRbTypeQuery("FXTreeItem *"));
        }
    #ifdef WITH_FXSCINTILLA
      else if(sender->isMemberOf(FXMETACLASS(FXScintilla))){
        if(type==SEL_COMMAND){
          return FXRbGetRubyObj(ptr,FXRbTypeQuery("SCNotification *"));
          }
        }
    #endif
      else{
        FXTRACE((100,"%s:%d: message data passed through as-is\n",__FILE__,__LINE__));
        return reinterpret_cast<VALUE>(ptr); // pass-through as is
        }
      FXTRACE((100,"%s:%d: message data passed through as-is\n",__FILE__,__LINE__));
      return reinterpret_cast<VALUE>(ptr); // pass-through as is
      }
    
    
    /**
     * When a Ruby instance (e.g. one of your widgets) calls handle() on another
     * object, e.g.
     *
     *     def onUpdAnswer(sender, sel, ptr)
     *       if theAnswerIsTwo?
     *         sender.handle(self, FXSEL(SEL_COMMAND,FXWindow::ID_SETVALUE), 2)
     *       else
     *         sender.handle(self, FXSEL(SEL_COMMAND,FXWindow::ID_SETVALUE), 3)
     *       end
     *       return 1
     *     end
     *
     * it's usually the case that this will get passed along to the underlying
     * C++ object. In that case, we need to convert the message data (e.g. the
     * Fixnums "2" or "3" in the example above) from Ruby objects back into
     * the appropriate C++ objects. That's what this function is for.
     */
    void* FXRbGetExpectedData(VALUE recv,FXSelector key,VALUE value){
      void *ptr;
      static FXint intValue;
      static FXint intRange[2];
      static FXdouble realValue;
      static FXdouble realRange[2];
      static FXString stringValue;
      static FXColor colorValue;
      FXushort type=FXSELTYPE(key);
      FXushort id=FXSELID(key);
    
      // Extract the FOX object (the receiver) from this Ruby instance
      FXObject* obj;
      Data_Get_Struct(recv,FXObject,obj);
    
      FXASSERT(type!=SEL_NONE);
      FXASSERT(type!=SEL_LAST);
      switch(type){
        case SEL_KEYPRESS:
        case SEL_KEYRELEASE:
        case SEL_LEFTBUTTONPRESS:
        case SEL_LEFTBUTTONRELEASE:
        case SEL_MIDDLEBUTTONPRESS:
        case SEL_MIDDLEBUTTONRELEASE:
        case SEL_RIGHTBUTTONPRESS:
        case SEL_RIGHTBUTTONRELEASE:
        case SEL_MOTION:
        case SEL_ENTER:
        case SEL_LEAVE:
        case SEL_FOCUSIN:
        case SEL_FOCUSOUT:
        case SEL_KEYMAP:
        case SEL_UNGRABBED:
        case SEL_PAINT:
        case SEL_CREATE:
        case SEL_DESTROY:
        case SEL_UNMAP:
        case SEL_MAP:
        case SEL_CONFIGURE:
        case SEL_SELECTION_LOST:
        case SEL_SELECTION_GAINED:
        case SEL_SELECTION_REQUEST:
        case SEL_RAISED:
        case SEL_LOWERED:
        case SEL_MOUSEWHEEL:
        case SEL_BEGINDRAG:
        case SEL_ENDDRAG:
        case SEL_LASSOED:
        case SEL_TIMEOUT:
        case SEL_CLIPBOARD_LOST:
        case SEL_CLIPBOARD_GAINED:
        case SEL_CLIPBOARD_REQUEST:
        case SEL_CHORE:
        case SEL_FOCUS_SELF:
        case SEL_FOCUS_RIGHT:
        case SEL_FOCUS_LEFT:
        case SEL_FOCUS_DOWN:
        case SEL_FOCUS_UP:
        case SEL_FOCUS_NEXT:
        case SEL_FOCUS_PREV:
        case SEL_DND_ENTER:
        case SEL_DND_LEAVE:
        case SEL_DND_DROP:
        case SEL_DND_MOTION:
        case SEL_DND_REQUEST:
        case SEL_PICKED:
          SWIG_Ruby_ConvertPtr(value,&ptr,FXRbTypeQuery("FXEvent *"),1);
          return ptr;
        case SEL_IO_READ:
        case SEL_IO_WRITE:
        case SEL_IO_EXCEPT:
          return 0; // should be an FXInputHandle?
        case SEL_SIGNAL:
          return reinterpret_cast<void*>(static_cast<long>(NUM2INT(value)));
        case SEL_CLOSE:
        case SEL_DELETE:
        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))){