/***********************************************************************
 * FXRuby -- the Ruby language bindings for the FOX GUI toolkit.
 * Copyright (c) 2001-2003 by J. 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@users.sourceforge.net".
 ***********************************************************************/

/// Layout hints for child widgets
enum {
  LAYOUT_NORMAL      = 0,                                   /// Default layout mode
  LAYOUT_SIDE_TOP    = 0,                                   /// Pack on top side (default)
  LAYOUT_SIDE_BOTTOM = 0x00000001,                          /// Pack on bottom side
  LAYOUT_SIDE_LEFT   = 0x00000002,                          /// Pack on left side
  LAYOUT_SIDE_RIGHT  = LAYOUT_SIDE_LEFT|LAYOUT_SIDE_BOTTOM, /// Pack on right side
  LAYOUT_FILL_COLUMN = 0x00000001,                          /// Matrix column is stretchable
  LAYOUT_FILL_ROW    = 0x00000002,                          /// Matrix row is stretchable
  LAYOUT_LEFT        = 0,                                   /// Stick on left (default)
  LAYOUT_RIGHT       = 0x00000004,                          /// Stick on right
  LAYOUT_CENTER_X    = 0x00000008,                          /// Center horizontally
  LAYOUT_FIX_X       = LAYOUT_RIGHT|LAYOUT_CENTER_X,        /// X fixed
  LAYOUT_TOP         = 0,                                   /// Stick on top (default)
  LAYOUT_BOTTOM      = 0x00000010,                          /// Stick on bottom
  LAYOUT_CENTER_Y    = 0x00000020,                          /// Center vertically
  LAYOUT_FIX_Y       = LAYOUT_BOTTOM|LAYOUT_CENTER_Y,       /// Y fixed
  LAYOUT_RESERVED_1  = 0x00000040,
  LAYOUT_RESERVED_2  = 0x00000080,
  LAYOUT_FIX_WIDTH   = 0x00000100,                          /// Width fixed
  LAYOUT_FIX_HEIGHT  = 0x00000200,                          /// height fixed
  LAYOUT_MIN_WIDTH   = 0,                                   /// Minimum width is the default
  LAYOUT_MIN_HEIGHT  = 0,                                   /// Minimum height is the default
  LAYOUT_FILL_X      = 0x00000400,                          /// Stretch or shrink horizontally
  LAYOUT_FILL_Y      = 0x00000800,                          /// Stretch or shrink vertically
  LAYOUT_FILL        = LAYOUT_FILL_X|LAYOUT_FILL_Y,         /// Stretch or shrink in both directions
  LAYOUT_EXPLICIT    = LAYOUT_FIX_X|LAYOUT_FIX_Y|LAYOUT_FIX_WIDTH|LAYOUT_FIX_HEIGHT   /// Explicit placement
  };


/// Frame border appearance styles (for subclasses)
enum {
  FRAME_NONE   = 0,                                     /// Default is no frame
  FRAME_SUNKEN = 0x00001000,                            /// Sunken border
  FRAME_RAISED = 0x00002000,                            /// Raised border
  FRAME_THICK  = 0x00004000,                            /// Thick border
  FRAME_GROOVE = FRAME_THICK,                           /// A groove or etched-in border
  FRAME_RIDGE  = FRAME_THICK|FRAME_RAISED|FRAME_SUNKEN, /// A ridge or embossed border
  FRAME_LINE   = FRAME_RAISED|FRAME_SUNKEN,             /// Simple line border
  FRAME_NORMAL = FRAME_SUNKEN|FRAME_THICK               /// Regular raised/thick border
  };


/// Packing style (for packers)
enum {
  PACK_NORMAL         = 0,              /// Default is each its own size
  PACK_UNIFORM_HEIGHT = 0x00008000,     /// Uniform height
  PACK_UNIFORM_WIDTH  = 0x00010000      /// Uniform width
  };
  
class FXCursor;
class FXAccelTable;
class FXComposite;


%typemap(check) FXint CHILD_WINDOW_INDEX {
  if ($1 < 0 || $1 >= arg1->numChildren()) {
    rb_raise(rb_eIndexError, "child window index out of bounds");
  }
}

%apply FXint CHILD_WINDOW_INDEX { FXint index };

%rename("windowCount") FXWindow::getWindowCount() const;

/// Base class for all windows
class FXWindow : public FXDrawable {
protected:
  FXCursor     *defaultCursor;          // Normal Cursor
  FXCursor     *dragCursor;             // Cursor during drag
  FXAccelTable *accelTable;             // Accelerator table
  FXObject     *target;                 // Target object
  FXSelector    message;                // Message ID
  FXint         xpos;                   // Window X Position
  FXint         ypos;                   // Window Y Position
  FXColor       backColor;              // Window background color
  FXString      tag;                    // Help tag
  FXuint        flags;                  // Window state flags
  FXuint        options;                // Window options
public:

  // Common DND types
  static FXDragType deleteType;         // Delete request
  static FXDragType textType;           // Ascii text request
  static FXDragType colorType;          // Color
  static FXDragType urilistType;        // URI List
  static const FXDragType stringType;   // Clipboard text type (pre-registered)
  static const FXDragType imageType;    // Clipboard image type (pre-registered)

protected:
#ifdef WIN32
//  virtual FXID GetDC() const;
//  virtual int ReleaseDC(FXID) const;
  virtual const char* GetClass() const;
#else
  void addColormapWindows();
  void remColormapWindows();
#endif

protected:
  FXWindow();
  FXWindow(FXApp* a,FXVisual *vis);
  FXWindow(FXApp* a,FXWindow* own,FXuint opts,FXint x,FXint y,FXint w,FXint h);
  static FXWindow* findDefault(FXWindow* window);
  static FXWindow* findInitial(FXWindow* window);
  virtual FXbool doesOverrideRedirect() const;

protected:

  // Window state flags
  enum {
    FLAG_SHOWN        = 0x00000001,     // Is shown
    FLAG_ENABLED      = 0x00000002,     // Able to receive input
    FLAG_UPDATE       = 0x00000004,     // Is subject to GUI update
    FLAG_DROPTARGET   = 0x00000008,     // Drop target
    FLAG_FOCUSED      = 0x00000010,     // Has focus
    FLAG_DIRTY        = 0x00000020,     // Needs layout
    FLAG_RECALC       = 0x00000040,     // Needs recalculation
    FLAG_TIP          = 0x00000080,     // Show tip
    FLAG_HELP         = 0x00000100,     // Show help
    FLAG_DEFAULT      = 0x00000200,     // Default widget
    FLAG_INITIAL      = 0x00000400,     // Initial widget
    FLAG_SHELL        = 0x00000800,     // Shell window
    FLAG_ACTIVE       = 0x00001000,     // Window is active
    FLAG_PRESSED      = 0x00002000,     // Button has been pressed
    FLAG_KEY          = 0x00004000,     // Keyboard key pressed
    FLAG_CARET        = 0x00008000,     // Caret is on
    FLAG_CHANGED      = 0x00010000,     // Window data changed
    FLAG_LASSO        = 0x00020000,     // Lasso mode
    FLAG_TRYDRAG      = 0x00040000,     // Tentative drag mode
    FLAG_DODRAG       = 0x00080000,     // Doing drag mode
    FLAG_SCROLLINSIDE = 0x00100000,     // Scroll only when inside
    FLAG_SCROLLING    = 0x00200000,     // Right mouse scrolling
    FLAG_OWNED        = 0x00400000      // Window handle owned by widget
    };

public:
  
  // Message handlers
  long onPaint(FXObject*,FXSelector,void* PTR_EVENT);
  long onMap(FXObject*,FXSelector,void* PTR_EVENT);
  long onUnmap(FXObject*,FXSelector,void* PTR_EVENT);
  long onConfigure(FXObject*,FXSelector,void* PTR_EVENT);
  long onUpdate(FXObject*,FXSelector,void* PTR_NULL);
  long onMotion(FXObject*,FXSelector,void* PTR_EVENT);
  long onMouseWheel(FXObject*,FXSelector,void* PTR_EVENT);
  long onEnter(FXObject*,FXSelector,void* PTR_EVENT);
  long onLeave(FXObject*,FXSelector,void* PTR_EVENT);
  long onLeftBtnPress(FXObject*,FXSelector,void* PTR_EVENT);
  long onLeftBtnRelease(FXObject*,FXSelector,void* PTR_EVENT);
  long onMiddleBtnPress(FXObject*,FXSelector,void* PTR_EVENT);
  long onMiddleBtnRelease(FXObject*,FXSelector,void* PTR_EVENT);
  long onRightBtnPress(FXObject*,FXSelector,void* PTR_EVENT);
  long onRightBtnRelease(FXObject*,FXSelector,void* PTR_EVENT);
  long onBeginDrag(FXObject*,FXSelector,void* PTR_EVENT);
  long onEndDrag(FXObject*,FXSelector,void* PTR_EVENT);
  long onDragged(FXObject*,FXSelector,void* PTR_EVENT);
  long onKeyPress(FXObject*,FXSelector,void* PTR_EVENT);
  long onKeyRelease(FXObject*,FXSelector,void* PTR_EVENT);
  long onUngrabbed(FXObject*,FXSelector,void* PTR_EVENT);
  long onDestroy(FXObject*,FXSelector,void* PTR_IGNORE);
  long onFocusSelf(FXObject*,FXSelector,void* PTR_IGNORE);
  long onFocusIn(FXObject*,FXSelector,void* PTR_EVENT);
  long onFocusOut(FXObject*,FXSelector,void* PTR_EVENT);
  long onSelectionLost(FXObject*,FXSelector,void* PTR_EVENT);
  long onSelectionGained(FXObject*,FXSelector,void* PTR_EVENT);
  long onSelectionRequest(FXObject*,FXSelector,void* PTR_EVENT);
  long onClipboardLost(FXObject*,FXSelector,void* PTR_EVENT);
  long onClipboardGained(FXObject*,FXSelector,void* PTR_EVENT);
  long onClipboardRequest(FXObject*,FXSelector,void* PTR_EVENT);
  long onDNDEnter(FXObject*,FXSelector,void* PTR_EVENT);
  long onDNDLeave(FXObject*,FXSelector,void* PTR_EVENT);
  long onDNDMotion(FXObject*,FXSelector,void* PTR_EVENT);
  long onDNDDrop(FXObject*,FXSelector,void* PTR_EVENT);
  long onDNDRequest(FXObject*,FXSelector,void* PTR_EVENT);
  long onCmdShow(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdHide(FXObject*,FXSelector,void* PTR_IGNORE);
  long onUpdToggleShown(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdToggleShown(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdRaise(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdLower(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdEnable(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdDisable(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdUpdate(FXObject*,FXSelector,void* PTR_IGNORE);
  long onUpdYes(FXObject*,FXSelector,void* PTR_IGNORE);
  long onCmdDelete(FXObject*,FXSelector,void* PTR_IGNORE);

public:

  // Message ID's common to most Windows
  enum {
    ID_NONE,
    ID_HIDE,            // ID_HIDE+FALSE
    ID_SHOW,            // ID_HIDE+TRUE
    ID_TOGGLESHOWN,
    ID_LOWER,
    ID_RAISE,
    ID_DELETE,
    ID_DISABLE,         // ID_DISABLE+FALSE
    ID_ENABLE,          // ID_DISABLE+TRUE
    ID_UNCHECK,         // ID_UNCHECK+FALSE
    ID_CHECK,           // ID_UNCHECK+TRUE
    ID_UNKNOWN,         // ID_UNCHECK+MAYBE
    ID_UPDATE,
    ID_AUTOSCROLL,
    ID_TIPTIMER,
    ID_HSCROLLED,
    ID_VSCROLLED,
    ID_SETVALUE,
    ID_SETINTVALUE,
    ID_SETREALVALUE,
    ID_SETSTRINGVALUE,
    ID_SETICONVALUE,
    ID_SETINTRANGE,
    ID_SETREALRANGE,
    ID_GETINTVALUE,
    ID_GETREALVALUE,
    ID_GETSTRINGVALUE,
    ID_GETICONVALUE,
    ID_GETINTRANGE,
    ID_GETREALRANGE,
    ID_SETHELPSTRING, 
    ID_GETHELPSTRING, 
    ID_SETTIPSTRING, 
    ID_GETTIPSTRING,
    ID_QUERY_TIP,
    ID_QUERY_HELP,
    ID_QUERY_MENU,
    ID_HOTKEY,
    ID_ACCEL,
    ID_UNPOST,
    ID_POST,
    ID_MDI_TILEHORIZONTAL,
    ID_MDI_TILEVERTICAL,
    ID_MDI_CASCADE,
    ID_MDI_MAXIMIZE,
    ID_MDI_MINIMIZE,
    ID_MDI_RESTORE,
    ID_MDI_CLOSE,
    ID_MDI_WINDOW,
    ID_MDI_MENUWINDOW,
    ID_MDI_MENUMINIMIZE,
    ID_MDI_MENURESTORE,
    ID_MDI_MENUCLOSE,
    ID_MDI_NEXT,
    ID_MDI_PREV,
    ID_LAST
    };

public:

#ifdef SWIGRUBY

  // Common DND type names
  %extend {
    static VALUE deleteTypeName() {
      return to_ruby(FXWindow::deleteTypeName);
    }

    static VALUE textTypeName() {
      return to_ruby(FXWindow::textTypeName);
    }

    static VALUE colorTypeName() {
      return to_ruby(FXWindow::colorTypeName);
    }

    static VALUE urilistTypeName() {
      return to_ruby(FXWindow::urilistTypeName);
    }
  }

#endif /* SWIGRUBY */

public:

  /// Constructor
  %extend {
    // Construct as a child of some other window
    FXWindow(FXComposite* p,FXuint opts=0,FXint x=0,FXint y=0,FXint w=0,FXint h=0){
      return new FXRbWindow(p,opts,x,y,w,h);
      }
  
    // Shell window constructor
    FXWindow(FXApp* a,FXVisual *vis){
      return new FXRbWindow(a,vis);
      }
    
    // Construct owned window
    FXWindow(FXApp* a,FXWindow* own,FXuint opts,FXint x,FXint y,FXint w,FXint h){
      return new FXRbWindow(a,own,opts,x,y,w,h);
      }
    }

  /// Return a pointer to the parent window 
  FXWindow* getParent() const;

  /// Return a pointer to the owner window 
  FXWindow* getOwner() const;

  /// Return a pointer to the shell window  
  FXWindow* getShell() const;

  /// Return a pointer to the root window 
  FXWindow* getRoot() const;

  /// Return a pointer to the next (sibling) window, if any
  FXWindow* getNext() const;

  /// Return a pointer to the previous (sibling) window , if any
  FXWindow* getPrev() const;

  /// Return a pointer to this window's first child window , if any
  FXWindow* getFirst() const;

  /// Return a pointer to this window's last child window, if any
  FXWindow* getLast() const;

  /// Return a pointer to the currently focused child window
  FXWindow* getFocus() const;

  /// Change window key
  void setKey(FXuint k);

  /// Return window key
  FXuint getKey() const;

  /// Set the message target object for this window
  void setTarget(FXObject *t);

  /// Get the message target object for this window, if any
  FXObject* getTarget() const;

  /// Set the message identifier for this window 
  void setSelector(FXSelector sel);

  /// Get the message identifier for this window 
  FXSelector getSelector() const;

  /// Get this window's x-coordinate, in the parent's coordinate system
  FXint getX() const;

  /// Get this window's y-coordinate, in the parent's coordinate system
  FXint getY() const;

  /// Set this window's x-coordinate, in the parent's coordinate system
  void setX(FXint x);

  /// Set this window's y-coordinate, in the parent's coordinate system
  void setY(FXint y);

  /// Set the window width 
  void setWidth(FXint w);

  /// Set the window height 
  void setHeight(FXint h);

  /// Set layout hints for this window 
  void setLayoutHints(FXuint lout);

  /// Get layout hints for this window 
  FXuint getLayoutHints() const;

  /// Return a pointer to the accelerator table 
  FXAccelTable* getAccelTable() const;

  /// Set the accelerator table 
  void setAccelTable(FXAccelTable* acceltable);

  /// Add a hot key
  void addHotKey(FXHotKey code);

  /// Remove a hot key 
  void remHotKey(FXHotKey code);

  /// Change help tag for this widget
  void setHelpTag(const FXString& text);

  /// Get the help tag for this widget
  FXString getHelpTag() const;

  /// Return true if window is a shell window
  FXbool isShell() const;

  /// Return true if specified window is owned by this window
  FXbool isOwnerOf(const FXWindow* window) const;

  /// Return true if specified window is ancestor of this window.
  FXbool isChildOf(const FXWindow* window) const;

  /// Return true if this window contains child in its subtree.
  FXbool containsChild(const FXWindow* child) const;

  /// Return the child window at specified coordinates
  FXWindow* getChildAt(FXint x,FXint y) const;

  /// Return the number of child windows for this window 
  FXint numChildren() const;

  /**
  * Return the index (starting from zero) of the specified child window, 
  * or -1 if the window is not a child or NULL
  */
  FXint indexOfChild(const FXWindow *window) const;

#ifdef SWIGRUBY

  %extend {
    // Remove specified child window
    FXbool removeChild(FXWindow* child){
      if(self->containsChild(child)){
        delete child;
        return TRUE;
        }
      else{
        return FALSE;
        }
      }

    // Returns an array containing all child windows of this window
    VALUE getChildren() const {
      VALUE ary=rb_ary_new();
      for(FXWindow* child=self->getFirst();child;child=child->getNext()){
        rb_ary_push(ary,FXRbGetRubyObj(child, "FXWindow *"));
        }
      return ary;
      }
  }

#endif

  /**
  * Return the child window at specified index, 
  * or NULL if the index is negative or out of range
  */
  FXWindow* childAtIndex(FXint index) const;

  /// Return the common ancestor of window a and window b
  static FXWindow* commonAncestor(FXWindow* a,FXWindow* b);

  /// Get number of existing windows
  static FXint getWindowCount() const;

  /// Set the default cursor for this window
  void setDefaultCursor(FXCursor* cur);

  /// Return the default cursor for this window 
  FXCursor* getDefaultCursor() const;

  /// Set the drag cursor for this window
  void setDragCursor(FXCursor* cur);

  /// Return the drag cursor for this window 
  FXCursor* getDragCursor() const;

#ifdef SWIGRUBY

  %extend {
    /// Return the cursor position and mouse button-state
    VALUE getCursorPosition() const {
      FXint x, y;
      FXuint buttons;
      self->getCursorPosition(x, y, buttons);
      VALUE arr = rb_ary_new();
      rb_ary_push(arr, INT2NUM(x));
      rb_ary_push(arr, INT2NUM(y));
      rb_ary_push(arr, UINT2NUM(buttons));
      return arr;
    }
  }

#endif

  /// Warp the cursor to the new position
  FXint setCursorPosition(FXint x,FXint y);

  /// Return true if this window is able to receive mouse and keyboard events
  FXbool isEnabled() const;

  /// Return true if the window is active
  FXbool isActive() const;

  /// Return true if this window has the focus
  FXbool hasFocus() const;

  /// Return true if this is the default window
  FXbool isDefault() const;
  
  /// Make this window the initial default window
  void setInitial(FXbool enable=TRUE);
  
  /// Return true if this is the initial default window
  FXbool isInitial() const;

  /// Force a GUI update of this window and its children 
  void forceRefresh();

  /// Scroll rectangle x,y,w,h by a shift of dx,dy
  void scroll(FXint x,FXint y,FXint w,FXint h,FXint dx,FXint dy) const;

  /// Mark the specified rectangle to be repainted later
  void update(FXint x,FXint y,FXint w,FXint h) const;

  /// Mark the entire window to be repainted later
  void update() const;

  /// If marked but not yet painted, paint the given rectangle now
  void repaint(FXint x,FXint y,FXint w,FXint h) const;
  
  /// If marked but not yet painted, paint the window now
  void repaint() const;

  /**
  * Grab the mouse to this window; future mouse events will be
  * reported to this window even while the cursor goes outside of this window
  */
  void grab();

  /// Release the mouse grab 
  void ungrab();

  /// Return true if the window has been grabbed
  FXbool grabbed() const;

  /// Grab keyboard device
  void grabKeyboard();

  /// Ungrab keyboard device
  void ungrabKeyboard();

  /// Return true if active grab is in effect
  FXbool grabbedKeyboard() const;

  /// Return true if the window is shown
  FXbool shown() const;

  /// Return true if the window is under the cursor
  FXbool underCursor() const;

  /// Return true if this window owns the primary selection
  FXbool hasSelection() const;

  %extend {
    /// Try to acquire the primary selection, given a list of drag types
    FXbool acquireSelection(VALUE typesArray){
      Check_Type(typesArray,T_ARRAY);
      FXDragType *types=0;
      FXuint numtypes=RARRAY(typesArray)->len;
      if(numtypes>0){
        types=new FXDragType[numtypes];
        for(FXuint i=0;i<numtypes;i++){
          types[i]=(FXDragType) NUM2USHRT(rb_ary_entry(typesArray,i));
          }
      }
      FXbool result=self->acquireSelection(types,numtypes);
      delete [] types;
      return result;
      }
  }

  /// Release the primary selection
  FXbool releaseSelection();

  /// Return true if this window owns the clipboard
  FXbool hasClipboard() const;

  %extend {
    /// Try to acquire the clipboard, given a list of drag types
    FXbool acquireClipboard(VALUE typesArray){
      Check_Type(typesArray,T_ARRAY);
      FXDragType *types=0;
      FXuint numtypes=RARRAY(typesArray)->len;
      if(numtypes>0){
        types=new FXDragType[numtypes];
        for(FXuint i=0;i<numtypes;i++){
          types[i]=(FXDragType) NUM2USHRT(rb_ary_entry(typesArray,i));
          }
      }
      FXbool result=self->acquireClipboard(types,numtypes);
      delete [] types;
      return result;
      }
  }

  /// Release the clipboard
  FXbool releaseClipboard();

  /// Enable this window to receive drops 
  void dropEnable();

  /// Disable this window from receiving drops
  void dropDisable();

  /// Return true if this window is able to receive drops
  FXbool isDropEnabled() const;

  /// Return true if a drag operaion has been initiated from this window
  FXbool isDragging() const;
  
  %extend {
    /// Initiate a drag operation with a list of previously registered drag types
    FXbool beginDrag(VALUE typesArray){
      Check_Type(typesArray,T_ARRAY);
      FXDragType *types=0;
      FXuint numtypes=RARRAY(typesArray)->len;
      if(numtypes>0){
        types=new FXDragType[numtypes];
        for(FXuint i=0;i<numtypes;i++){
          types[i]=(FXDragType) NUM2USHRT(rb_ary_entry(typesArray,i));
          }
      }
      FXbool result=self->beginDrag(types,numtypes);
      delete [] types;
      return result;
      }
  }
  
  /**
  * When dragging, inform the drop-target of the new position and
  * the drag action
  */
  FXbool handleDrag(FXint x,FXint y,FXDragAction action=DRAG_COPY);
  
  /// Terminate the drag operation with or without actually dropping the data
  FXbool endDrag(FXbool drop=TRUE);
  
  /// Return true if this window is the target of a drop
  FXbool isDropTarget() const;
  
  /**
  * When being dragged over, indicate that no further SEL_DND_MOTION messages
  * are required while the cursor is inside the given rectangle
  */
  void setDragRectangle(FXint x,FXint y,FXint w,FXint h,FXbool wantupdates=TRUE) const;
  
  /**
  * When being dragged over, indicate we want to receive SEL_DND_MOTION messages
  * every time the cursor moves
  */
  void clearDragRectangle() const;
  
  /// When being dragged over, indicate acceptance or rejection of the dragged data
  void acceptDrop(FXDragAction action=DRAG_ACCEPT) const;
  
  /// The target accepted our drop
  FXDragAction didAccept() const;
  
#ifdef SWIGRUBY

  %extend {
    // When being dragged over, inquire the drag types which are being offered 
    VALUE inquireDNDTypes(FXDNDOrigin origin) const {
      FXDragType* types;
      FXuint numtypes;
      VALUE arr = rb_ary_new();
      if (self->inquireDNDTypes(origin, types, numtypes)) {
        for (FXuint i = 0; i < numtypes; i++)
          rb_ary_push(arr, to_ruby(types[i]));
        FXFREE(&types);
      }
      return arr;
    }
  }

#endif
  
  /// When being dragged over, return true if we are offered the given drag type
  FXbool offeredDNDType(FXDNDOrigin origin,FXDragType type) const;
  
  /// When being dragged over, return the drag action
  FXDragAction inquireDNDAction() const;
  
#ifdef SWIGRUBY

  %extend {
    // Set DND data; ownership is transferred to the system
    void setDNDData(FXDNDOrigin origin, FXDragType type, VALUE str) const {
      Check_Type(str, T_STRING);
      FXuchar* data;
      FXuint size = RSTRING(str)->len;
      if (FXMALLOC(&data, FXuchar, size)) {
        memcpy((void *) data, (void *) RSTRING(str)->ptr, size);
        self->setDNDData(origin, type, data, size);
      } else {
        rb_raise(rb_eNoMemError, "couldn't copy drag-and-drop data");
      }
    }

    // Get DND data; the caller becomes the owner of the array.
    VALUE getDNDData(FXDNDOrigin origin, FXDragType type) const {
      FXuchar* data;
      FXuint size;
      VALUE result = Qnil;
      if (self->getDNDData(origin, type, data, size)) {
        result = rb_str_new((const FXchar *) data, size);
        FXFREE(&data);
      }
      return result;
    }
  }

#endif /* SWIGRUBY */
  
#ifdef SWIGRUBY

  %extend {
    // Translate coordinates from fromwindow's coordinate space
    // to this window's coordinate space
    VALUE translateCoordinatesFrom(const FXWindow* fromwindow,
                                   FXint fromx, FXint fromy) const {
      FXint tox, toy;
      self->translateCoordinatesFrom(tox, toy, fromwindow, fromx, fromy);
      VALUE result = rb_ary_new();
      rb_ary_push(result, INT2NUM(tox));
      rb_ary_push(result, INT2NUM(toy));
      return result;
    }
  
    // Translate coordinates from this window's coordinate space
    // to towindow's coordinate space
    VALUE translateCoordinatesTo(const FXWindow* towindow,
                                 FXint fromx, FXint fromy) const {
      FXint tox, toy;
      self->translateCoordinatesTo(tox, toy, towindow, fromx, fromy);
      VALUE result = rb_ary_new();
      rb_ary_push(result, INT2NUM(tox));
      rb_ary_push(result, INT2NUM(toy));
      return result;
    }
  }
  
#endif /* SWIGRUBY */

  /// Get background color
  FXColor getBackColor() const;

  /// Relink this window before sibling in the window list
  void linkBefore(FXWindow* sibling);
  
  /// Relink this window after sibling in the window list
  void linkAfter(FXWindow* sibling);

  /// Destroy window
  virtual ~FXWindow();
  };

%clear FXint index;

DECLARE_FXOBJECT_VIRTUALS(FXWindow)
DECLARE_FXID_VIRTUALS(FXWindow)
DECLARE_FXDRAWABLE_VIRTUALS(FXWindow)
DECLARE_FXWINDOW_VIRTUALS(FXWindow)

%{
static swig_type_info *FXWindow_dynamic_cast(void **ptr) {
    FXWindow **ppWindow = reinterpret_cast<FXWindow **>(ptr);
    FXCanvas *pCanvas=dynamic_cast<FXCanvas*>(*ppWindow);
    if(pCanvas){
      *ptr=reinterpret_cast<void*>(pCanvas);
      return SWIG_TypeQuery("FXCanvas *");
      }
    FXComposite *pComposite=dynamic_cast<FXComposite*>(*ppWindow);
    if(pComposite){
      *ptr=reinterpret_cast<void*>(pComposite);
      return SWIG_TypeQuery("FXComposite *");
      }
    FXDragCorner *pDragCorner=dynamic_cast<FXDragCorner*>(*ppWindow);
    if(pDragCorner){
      *ptr=reinterpret_cast<void*>(pDragCorner);
      return SWIG_TypeQuery("FXDragCorner *");
      }
    FXFrame *pFrame=dynamic_cast<FXFrame*>(*ppWindow);
    if(pFrame){
      *ptr=reinterpret_cast<void*>(pFrame);
      return SWIG_TypeQuery("FXFrame *");
      }
    FXMenuCaption *pMenuCaption=dynamic_cast<FXMenuCaption*>(*ppWindow);
    if(pMenuCaption){
      *ptr=reinterpret_cast<void*>(pMenuCaption);
      return SWIG_TypeQuery("FXMenuCaption *");
      }
    FXMenuSeparator *pMenuSeparator=dynamic_cast<FXMenuSeparator*>(*ppWindow);
    if(pMenuSeparator){
      *ptr=reinterpret_cast<void*>(pMenuSeparator);
      return SWIG_TypeQuery("FXMenuSeparator *");
      }
    FXScrollBar *pScrollBar=dynamic_cast<FXScrollBar*>(*ppWindow);
    if(pScrollBar){
      *ptr=reinterpret_cast<void*>(pScrollBar);
      return SWIG_TypeQuery("FXScrollBar *");
      }
    FXScrollCorner *pScrollCorner=dynamic_cast<FXScrollCorner*>(*ppWindow);
    if(pScrollCorner){
      *ptr=reinterpret_cast<void*>(pScrollCorner);
      return SWIG_TypeQuery("FXScrollCorner *");
      }
    FXToolBarGrip *pToolBarGrip=dynamic_cast<FXToolBarGrip*>(*ppWindow);
    if(pToolBarGrip){
      *ptr=reinterpret_cast<void*>(pToolBarGrip);
      return SWIG_TypeQuery("FXToolBarGrip *");
      }
    return 0;
}
%}

DYNAMIC_CAST(SWIGTYPE_p_FXWindow, FXWindow_dynamic_cast);

