//
// Copyright (C) 1999-2004 Toshikaz Hirabayashi
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
// TOSHIKAZ HIRABAYASHI BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
// OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
//
// Except as contained in this notice, the name of Toshikaz Hirabayashi shall
// not be used in advertising or otherwise to promote the sale, use or other
// dealings in this Software without prior written authorization from
// Toshikaz Hirabayashi.

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <WSCdevice.h>
#include <WSCcolorSet.h>
#include <WSCimageSet.h>
#include <WSCbase.h>
#include <WSDmouse.h>
#include <WSCbaseList.h>
#include <x11/WSDxmwinDev.h>
#include <x11/WSDxappDev.h>
#include <x11/WSDxdraw.h>
#include <x11/WSxcom.h>
#include <x11/WSDxdragDrop.h>
#include <x11/WSDxformDev.h>
#include <x11/WSDxnwDev.h>
#include <form.h>

#ifndef MacOS
#include <dlfcn.h>
#else //MacOS
//#include <mach-o/dyld.h>
#define RTLD_LAZY 0
extern void* dlopen(char* fname,long);
extern void* dlsym(void*,char* procn);
#endif //MacOS

WSMFclassInit(WSDxmwinDev,WSDmwindowDev);

WSDdev* _wsdxmwindev_init_(){
  return new WSDxmwinDev();
}

class _WSDxmwinDev_init_ {
  public:_WSDxmwinDev_init_(){
     WSGIappDevice()->setCreateHandler("mwindowDev",_wsdxmwindev_init_);
  };
};
static _WSDxmwinDev_init_ _init_to_run_WSDxmwinDev_;

//static WSDxdraw* draw_of_xmwin = NULL;

int red_mask, green_mask, blue_mask;
int red_shift, green_shift, blue_shift;
int start_shift;
unsigned int start_mask;
char mask_initialized = 0;
long msb_flag = 0;

WSDxmwinDev::WSDxmwinDev(){
  _pixmap  = 0;
  _pixmap_for_img  = 0;
  _gc      = 0;
  _image   = NULL;
  _display = NULL;
  _bit = 0; 
//  if (draw_of_xmwin == NULL){
//      draw_of_xmwin = new WSDxdraw();
//  }
//  setDraw(draw_of_xmwin);
}

WSDxmwinDev::~WSDxmwinDev(){
  destroyContext();
  destroyPixmap();
}

long WSDxmwinDev::copyToWindow(WSDdev* dest,short x,short y,WSCushort w,WSCushort h,short dx,short dy){
  if (_pixmap == 0 || _gc == 0){
    return WS_ERR;
  }
  if (dest->cast("WSDnwDev") != NULL){
    int vx = 0;
    int vy = 0;
    if (dest->getAttachedClient() != NULL){
      vx = dest->getAttachedClient()->getProperty(WSNx);
      vy = dest->getAttachedClient()->getProperty(WSNy);
    }
    WSDdev* pdev = dest->getParentDev();
    WSDxformDev* xdev = NULL;
    if (pdev != NULL){
      xdev = (WSDxformDev*)dest->getParentDev()->cast("WSDxformDev");
    }
    if ( (Window)dest->getWindowResource() != (Window)-1){
      XCopyArea( WSGIxwinAppDev()->display(),_pixmap,
             (Window)dest->getWindowResource(),_gc,
            (int)x, (int)y, (WSCuint)w, (WSCuint)h, vx+(int)dx, vy+(int)dy);
    }
    if (xdev != NULL && xdev->getPixmapStyle() != WS_DIRECT_WINDOW &&
             (Widget)xdev->getSpecialResource() != NULL ){
      XCopyArea( WSGIxwinAppDev()->display(),_pixmap,
             XtWindow((Widget)xdev->getSpecialResource()),_gc,
            (int)x, (int)y, (WSCuint)w, (WSCuint)h, vx+(int)dx, vy+(int)dy);
    }
  }else{
    if ( (Window)dest->getWindowResource() != (Window)-1){
      XCopyArea( WSGIxwinAppDev()->display(),_pixmap,
             (Window)dest->getWindowResource(),_gc,
            (int)x, (int)y, (WSCuint)w, (WSCuint)h, (int)dx, (int)dy);
    }
    WSDxformDev* xdev = (WSDxformDev*)dest->cast("WSDxformDev");
    if (xdev != NULL && xdev->getPixmapStyle() != WS_DIRECT_WINDOW &&
             (Widget)xdev->getSpecialResource() != NULL ){
      XCopyArea( WSGIxwinAppDev()->display(),_pixmap,
             XtWindow((Widget)xdev->getSpecialResource()),_gc,
            (int)x, (int)y, (WSCuint)w, (WSCuint)h, (int)dx, (int)dy);
    }
  }
  return WS_NO_ERR;
}
long WSDxmwinDev::copyToWindowWithMask(WSDdev* dest,short x,short y,
                                       WSCushort w,WSCushort h,short dx,short dy,
                                       WSDimage* image){
  if (image == NULL){
    return WS_ERR;
  }

  Pixmap mask = (Pixmap)image->getValue1();
  return _copyToWindowWithMask(dest,x,y,w,h,dx,dy,mask);

}
long WSDxmwinDev::_copyToWindowWithMask(WSDdev* dest,short x,short y,
                                       WSCushort w,WSCushort h,short dx,short dy,
                                       Pixmap mask){
  if (_pixmap == 0 || _gc == 0){
    return WS_ERR;
  }
  GC gc2 = WSGIxwinAppDev()->appGC2();
  if (gc2 == 0){
    return WS_ERR;
  }

  Pixmap src = WSGFxGetPixmap(w,h);
  XCopyArea( WSGIxwinAppDev()->display(),_pixmap,
           src,gc2, (int)x, (int)y, (WSCuint)w, (WSCuint)h, 0,0);

//  Pixmap mask = (Pixmap)image->getValue1();

  WSDxnwDev* nwdev = (WSDxnwDev*)dest->cast("WSDxnwDev");
  int vx = 0;
  int vy = 0;
  WSDdev* pdev = dest->getParentDev();
  WSDxformDev* xdev = NULL;
  if (nwdev != NULL){
    if (dest->getAttachedClient() != NULL){
      vx = dest->getAttachedClient()->getProperty(WSNx);
      vy = dest->getAttachedClient()->getProperty(WSNy);
    }
    if (pdev != NULL){
      xdev = (WSDxformDev*)dest->getParentDev()->cast("WSDxformDev");
    }
  }else{
    xdev = (WSDxformDev*)dest->cast("WSDxformDev");
  }

  Pixmap tdest = WSGFxGetPixmap(w,h);
  if (xdev != NULL){
    XSetFunction( WSGIxwinAppDev()->display(),gc2,GXcopy);
//    XSetGraphicsExposures(WSGIxwinAppDev()->display(),_gc,0);
    XCopyArea( WSGIxwinAppDev()->display(),
             xdev->getWindowResource(),
             tdest,gc2,
             vx+(int)dx, vy+(int)dy, (WSCuint)w, (WSCuint)h,0,0);
  }
  if (mask != (Pixmap)-1 && mask != 0){
    XSetFunction( WSGIxwinAppDev()->display(),gc2,GXand);
    XCopyArea( WSGIxwinAppDev()->display(),mask,src,gc2,
           (int)x, (int)y, (WSCuint)w, (WSCuint)h, 0,0);

    XSetGraphicsExposures(WSGIxwinAppDev()->display(),_gc,0);
    XSetFunction( WSGIxwinAppDev()->display(),_gc,GXandInverted);
    XSetFunction( WSGIxwinAppDev()->display(),gc2,GXandInverted);
    if (nwdev != NULL){
      if (nwdev->getUsePixmap() != False){
        XCopyArea( WSGIxwinAppDev()->display(),mask,
               nwdev->getWindowResource(),_gc,
              (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)dx, (int)dy);
      }else
      if ( (Window)dest->getWindowResource() != (Window)-1){
        XCopyArea( WSGIxwinAppDev()->display(),mask,
//               (Window)dest->getWindowResource(),_gc,
               (Window)tdest,gc2,
//              (int)0, (int)0, (WSCuint)w, (WSCuint)h, vx+(int)dx, vy+(int)dy);
              (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)0,(int)0);
      }
#if 0
      if (xdev != NULL && xdev->getPixmapStyle() != WS_DIRECT_WINDOW &&
               (Widget)xdev->getSpecialResource() != NULL ){
        XCopyArea( WSGIxwinAppDev()->display(),mask,
               XtWindow((Widget)xdev->getSpecialResource()),_gc,
              (int)0, (int)0, (WSCuint)w, (WSCuint)h, vx+(int)dx, vy+(int)dy);
      }
#endif

    }else{
      if ( (Window)dest->getWindowResource() != (Window)-1){
        XCopyArea( WSGIxwinAppDev()->display(),mask,
//               (Window)dest->getWindowResource(),_gc,
               (Window)tdest,gc2,
//              (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)dx, (int)dy);
              (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)0, (int)0);
      }
#if 0
      if (xdev != NULL && xdev->getPixmapStyle() != WS_DIRECT_WINDOW &&
               (Widget)xdev->getSpecialResource() != NULL ){
        XCopyArea( WSGIxwinAppDev()->display(),mask,
               XtWindow((Widget)xdev->getSpecialResource()),_gc,
              (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)dx, (int)dy);
      }
#endif
    }
  } 
  XSetFunction( WSGIxwinAppDev()->display(),_gc,GXor);
  XSetFunction( WSGIxwinAppDev()->display(),gc2,GXor);
  if (nwdev != NULL){
    if (nwdev->getUsePixmap() != False){
      XCopyArea( WSGIxwinAppDev()->display(),src,
             nwdev->getWindowResource(),_gc,
            (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)dx, (int)dy);
    }else
    if ( (Window)dest->getWindowResource() != (Window)-1){
      XCopyArea( WSGIxwinAppDev()->display(),src,
//             (Window)dest->getWindowResource(),_gc,
             (Window)tdest,gc2,
//            (int)0, (int)0, (WSCuint)w, (WSCuint)h, vx+(int)dx, vy+(int)dy);
            (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)0,(int)0);
    }
    XSetFunction( WSGIxwinAppDev()->display(),_gc,GXcopy);
    if (nwdev->getUsePixmap() != False){
    }else
    if ( (Window)dest->getWindowResource() != (Window)-1){
//      XCopyArea( WSGIxwinAppDev()->display(),src,
      XCopyArea( WSGIxwinAppDev()->display(),tdest,
             (Window)dest->getWindowResource(),_gc,
            (int)0, (int)0, (WSCuint)w, (WSCuint)h, vx+(int)dx, vy+(int)dy);
    }
//    XSetFunction( WSGIxwinAppDev()->display(),_gc,GXcopy);
    if (xdev != NULL && xdev->getPixmapStyle() != WS_DIRECT_WINDOW &&
             (Widget)xdev->getSpecialResource() != NULL ){
//      XCopyArea( WSGIxwinAppDev()->display(),src,
      XCopyArea( WSGIxwinAppDev()->display(),tdest,
             XtWindow((Widget)xdev->getSpecialResource()),_gc,
            (int)0, (int)0, (WSCuint)w, (WSCuint)h, vx+(int)dx, vy+(int)dy);
    }
  }else{
    if ( (Window)dest->getWindowResource() != (Window)-1){
      XCopyArea( WSGIxwinAppDev()->display(),src,
//             (Window)dest->getWindowResource(),_gc,
             (Window)tdest,_gc,
//            (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)dx, (int)dy);
            (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)0, (int)0);
    }
    XSetFunction( WSGIxwinAppDev()->display(),_gc,GXcopy);

    if (xdev != NULL && xdev->getPixmapStyle() != WS_DIRECT_WINDOW &&
             (Widget)xdev->getSpecialResource() != NULL ){
//      XCopyArea( WSGIxwinAppDev()->display(),src,
      XCopyArea( WSGIxwinAppDev()->display(),tdest,
             XtWindow((Widget)xdev->getSpecialResource()),_gc,
            (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)dx, (int)dy);
    }
  }
  WSGFxReleasePixmap(src);
  WSGFxReleasePixmap(tdest);
  XSetGraphicsExposures(WSGIxwinAppDev()->display(),_gc,1);
  XSetFunction( WSGIxwinAppDev()->display(),gc2,GXcopy);

  return WS_NO_ERR;
}
long WSDxmwinDev::copyToWindowWithMask(WSDdev* dest,short x,short y,
                                       WSCushort w,WSCushort h,short dx,short dy,
                                       WSDmwindowDev* image){
  if (image == NULL){
    return WS_ERR;
  }
  WSDxmwinDev* mimage = (WSDxmwinDev*)image->cast("WSDxmwinDev");
  if (mimage == NULL){
    return WS_ERR;
  }
  Pixmap mask = (Pixmap)mimage->_pixmap;
  return _copyToWindowWithMask(dest,x,y,w,h,dx,dy,mask);

#if 0
  if (_pixmap == 0 || _gc == 0){
    return WS_ERR;
  }
  GC gc2 = WSGIxwinAppDev()->appGC2();
  if (gc2 == 0){
    return WS_ERR;
  }
//printf("WSDxmwinDev::copyToWindowWithMask gc=0x%x\n",_gc);
  Pixmap src = WSGFxGetPixmap(w,h);
  XCopyArea( WSGIxwinAppDev()->display(),_pixmap,
           src,gc2, (int)x, (int)y, (WSCuint)w, (WSCuint)h, 0,0);

  WSDxmwinDev* mimage = (WSDxmwinDev*)image->cast("WSDxmwinDev");
  if (mimage == NULL){
    WSGFxReleasePixmap(src);
    return WS_ERR;
  }
  Pixmap mask = (Pixmap)mimage->_pixmap;
  WSDxnwDev* nwdev = (WSDxnwDev*)dest->cast("WSDxnwDev");
  int vx = 0;
  int vy = 0;
  WSDdev* pdev = dest->getParentDev();
  WSDxformDev* xdev = NULL;
  if (nwdev != NULL){
    if (dest->getAttachedClient() != NULL){
      vx = dest->getAttachedClient()->getProperty(WSNx);
      vy = dest->getAttachedClient()->getProperty(WSNy);
    }
    if (pdev != NULL){
      xdev = (WSDxformDev*)dest->getParentDev()->cast("WSDxformDev");
    }
  }else{
    xdev = (WSDxformDev*)dest->cast("WSDxformDev");
  }
  Pixmap tdest = WSGFxGetPixmap(w,h);
  if (xdev != NULL){
    XSetFunction( WSGIxwinAppDev()->display(),gc2,GXcopy);
//    XSetGraphicsExposures(WSGIxwinAppDev()->display(),_gc,0);
    XCopyArea( WSGIxwinAppDev()->display(),
             xdev->getWindowResource(),
             tdest,gc2,
             vx+(int)dx, vy+(int)dy, (WSCuint)w, (WSCuint)h,0,0);
  }

  if (mask != (Pixmap)-1 && mask != 0){
    XSetFunction( WSGIxwinAppDev()->display(),gc2,GXand);
    XCopyArea( WSGIxwinAppDev()->display(),mask,src,gc2,
           (int)x, (int)y, (WSCuint)w, (WSCuint)h, 0,0);

    XSetGraphicsExposures(WSGIxwinAppDev()->display(),_gc,0);
    XSetFunction( WSGIxwinAppDev()->display(),_gc,GXandInverted);
    XSetFunction( WSGIxwinAppDev()->display(),gc2,GXandInverted);
    if (nwdev != NULL){
      if (nwdev->getUsePixmap() != False){
        XCopyArea( WSGIxwinAppDev()->display(),mask,
               nwdev->getWindowResource(),_gc,
              (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)dx, (int)dy);
//printf("UsePixmap copy %d %d %d %d -> %d,%d\n",0,0,w,h,vx+dx,vy+dy);
      }else if ( (Window)dest->getWindowResource() != (Window)-1){
//printf("window copy %d %d %d %d -> %d,%d\n",0,0,w,h,0,0);
        XCopyArea( WSGIxwinAppDev()->display(),mask,
//             (Window)dest->getWindowResource(),_gc,
             (Window)tdest,gc2,
//              (int)0, (int)0, (WSCuint)w, (WSCuint)h, vx+(int)dx, vy+(int)dy);
              (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)0, (int)0);
      }
#if 0
      if (xdev != NULL && xdev->getPixmapStyle() != WS_DIRECT_WINDOW &&
               (Widget)xdev->getSpecialResource() != NULL ){
        XCopyArea( WSGIxwinAppDev()->display(),mask,
               XtWindow((Widget)xdev->getSpecialResource()),_gc,
              (int)0, (int)0, (WSCuint)w, (WSCuint)h, vx+(int)dx, vy+(int)dy);
      }
#endif

    }else{
      if ( (Window)dest->getWindowResource() != (Window)-1){
        XCopyArea( WSGIxwinAppDev()->display(),mask,
//               (Window)dest->getWindowResource(),_gc,
               (Window)tdest,gc2,
//              (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)dx, (int)dy);
              (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)0, (int)0);
      }
#if 0
      WSDxformDev* xdev = (WSDxformDev*)dest->cast("WSDxformDev");
      if (xdev != NULL && xdev->getPixmapStyle() != WS_DIRECT_WINDOW &&
               (Widget)xdev->getSpecialResource() != NULL ){
        XCopyArea( WSGIxwinAppDev()->display(),mask,
               XtWindow((Widget)xdev->getSpecialResource()),_gc,
              (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)dx, (int)dy);
      }
#endif
    }
  } 
  XSetFunction( WSGIxwinAppDev()->display(),_gc,GXor);
  XSetFunction( WSGIxwinAppDev()->display(),gc2,GXor);
  if (nwdev != NULL){
    if (nwdev->getUsePixmap() != False){
      XCopyArea( WSGIxwinAppDev()->display(),src,
            nwdev->getWindowResource(),_gc,
            (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)dx, (int)dy);
    }else if ( (Window)dest->getWindowResource() != (Window)-1){
//printf("window copy1 %d %d %d %d -> %d,%d\n",0,0,w,h,0,0);
      XCopyArea( WSGIxwinAppDev()->display(),src,
//             (Window)dest->getWindowResource(),_gc,
             (Window)tdest,gc2,
//            (int)0, (int)0, (WSCuint)w, (WSCuint)h, vx+(int)dx, vy+(int)dy);
            (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)0, (int)0);
    }
    XSetFunction( WSGIxwinAppDev()->display(),_gc,GXcopy);
    if (nwdev->getUsePixmap() != False){
    }else
    if ( (Window)dest->getWindowResource() != (Window)-1){
//printf("window copy2 %d %d %d %d -> %d,%d\n",0,0,w,h,dx+vx,dy+vy);
//      XCopyArea( WSGIxwinAppDev()->display(),src,
      XCopyArea( WSGIxwinAppDev()->display(),tdest,
             (Window)dest->getWindowResource(),_gc,
            (int)0, (int)0, (WSCuint)w, (WSCuint)h, vx+(int)dx, vy+(int)dy);
    }
    if (xdev != NULL && xdev->getPixmapStyle() != WS_DIRECT_WINDOW &&
             (Widget)xdev->getSpecialResource() != NULL ){
//printf("window copy3 %d %d %d %d -> %d,%d\n",0,0,w,h,0,0);
//      XCopyArea( WSGIxwinAppDev()->display(),src,
      XCopyArea( WSGIxwinAppDev()->display(),tdest,
             XtWindow((Widget)xdev->getSpecialResource()),_gc,
            (int)0, (int)0, (WSCuint)w, (WSCuint)h, vx+(int)dx, vy+(int)dy);
    }

  }else{
    if ( (Window)dest->getWindowResource() != (Window)-1){
      XCopyArea( WSGIxwinAppDev()->display(),src,
//             (Window)dest->getWindowResource(),_gc,
             (Window)tdest,gc2,
//            (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)dx, (int)dy);
            (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)0, (int)0);
    }
    XSetFunction( WSGIxwinAppDev()->display(),_gc,GXcopy);
//    WSDxformDev* xdev = (WSDxformDev*)dest->cast("WSDxformDev");
    if (xdev != NULL && xdev->getPixmapStyle() != WS_DIRECT_WINDOW &&
             (Widget)xdev->getSpecialResource() != NULL ){
//      XCopyArea( WSGIxwinAppDev()->display(),src,
      XCopyArea( WSGIxwinAppDev()->display(),tdest,
             XtWindow((Widget)xdev->getSpecialResource()),_gc,
            (int)0, (int)0, (WSCuint)w, (WSCuint)h, (int)dx, (int)dy);
    }
  }
  WSGFxReleasePixmap(src);
  WSGFxReleasePixmap(tdest);
  XSetGraphicsExposures(WSGIxwinAppDev()->display(),_gc,1);
  XSetFunction( WSGIxwinAppDev()->display(),gc2,GXcopy);
  return WS_NO_ERR;
#endif
}

long WSDxmwinDev::copyFromWindow(WSDdev* dest,short x,short y,WSCushort w,WSCushort h,short dx,short dy){
  if (_pixmap == 0 || _gc == 0){
    return WS_ERR;
  }
  if (dest->cast("WSDnwDev") != NULL){
    int vx = 0;
    int vy = 0;
    if (dest->getAttachedClient() != NULL){
      vx = dest->getAttachedClient()->getProperty(WSNx);
      vy = dest->getAttachedClient()->getProperty(WSNy);
    }
    XCopyArea( WSGIxwinAppDev()->display(),
             (Window)dest->getWindowResource(),_pixmap,_gc,
          vx+(int)x, vy+(int)y, (WSCuint)w, (WSCuint)h, (int)dx, (int)dy);
  }else{
    XCopyArea( WSGIxwinAppDev()->display(),
             (Window)dest->getWindowResource(),_pixmap,_gc,
          (int)x, (int)y, (WSCuint)w, (WSCuint)h, (int)dx, (int)dy);
  }
  return WS_NO_ERR;
}

long WSDxmwinDev::createPixmap(WSCushort w,WSCushort h){
  _w = w;
  _h = h;
  if (_w == 0 || _h == 0){
    return WS_ERR;
  }

  if (_pixmap != 0){
    destroyPixmap();
  }
  _pixmap = WSGFxGetPixmap(w,h);
  createContext();
  return WS_NO_ERR;
}
long WSDxmwinDev::destroyPixmap(){
  if (_pixmap != 0){
    WSGFxReleasePixmap(_pixmap);
    _pixmap = 0;
  }
  destroyContext();
  return WS_NO_ERR;
}

long WSDxmwinDev::getDeviceResource(){
  return (long)WSGIxwinAppDev()->display();
}


long WSDxmwinDev::getContextResource(){
  if (_gc == 0){
    return -1;
  }
  return (long)_gc;
}

long WSDxmwinDev::getSpecialResource(){
   return (long)0;
}

long WSDxmwinDev::createContext(){
  destroyContext();  
  WSDxappDev* app   = WSGIxwinAppDev();
  _gc = app->appGC();
  return WS_NO_ERR;
}

long WSDxmwinDev::getWindowResource(){
  return (long)_pixmap;
}

long WSDxmwinDev::destroyContext(){
 _gc = 0;
 return WS_NO_ERR;
}

long WSDxmwinDev::initBuffer(){
  if (_image != NULL){
    if (_image->data != NULL){
      delete _image->data;
      _image->data = NULL;
    }
    XDestroyImage(_image);
    _image = NULL;
  }
  Display* display = WSGIxwinAppDev()->display();
  _image = XGetImage(display,_pixmap,0,0,_w,_h,
                    0xffffffff,ZPixmap);

  _bit = XDefaultDepth(display,XDefaultScreen(display));

  if (_image != NULL){
    _pixmap_for_img = _pixmap;
    return WS_NO_ERR;
  }
  return WS_ERR;
}
void mask_init(){
  XWindowAttributes win_attr;

  Display* display = WSGIxwinAppDev()->display();
  msb_flag = (ImageByteOrder(display) == MSBFirst)?1:0;

  if (XGetWindowAttributes(display,
            RootWindow(display, DefaultScreen(display)), &win_attr) == 0){
    return;
  }
  if ((win_attr.depth == 24) || (win_attr.depth == 16)) {
    if (win_attr.depth == 24) {
      start_shift = 24;
      start_mask = 0x80000000;
    }else{
      start_shift = 8;
      start_mask = 0x8000;
    }
    red_mask = win_attr.visual->red_mask;
    red_shift = start_shift;
    unsigned int n = start_mask;
    while (!(n & red_mask)) {
      n >>= 1;
      red_shift--;
    }
    green_mask = win_attr.visual->green_mask;
    green_shift = start_shift;
    n = start_mask;
    while (!(n & green_mask)) {
      n >>= 1;
      green_shift--;
    }
    blue_mask = win_attr.visual->blue_mask;
    blue_shift = start_shift;
    n = start_mask;
    while (!(n & blue_mask)) {
      n >>= 1;
      blue_shift--;
    }
  }

  mask_initialized = 1;
}

long WSDxmwinDev::setBufferRGB(WSCushort x,WSCushort y,WSCuchar r,WSCuchar g,WSCuchar b){
  if (mask_initialized == 0){
    mask_init();
  }
  if (_image == NULL){
    return WS_ERR;
  }
  if (x < _w && y < _h){
    WSCulong udat;
    if (_bit > 16){
      udat = 0;
      if (red_shift >= 0){
        udat |= (((int)r << red_shift) & red_mask);
      }else{
        udat |= (((int)r >> (-red_shift)) & red_mask);
      }
      if (green_shift >= 0){
        udat |= (((int)g << green_shift) & green_mask);
      }else{
        udat |= (((int)g >> (-green_shift)) & green_mask);
      }
      if (blue_shift >= 0){
        udat |= (((int)b << blue_shift) & blue_mask);
      }else{
        udat |= (((int)b >> (-blue_shift)) & blue_mask);
      }
      if (_image != NULL){
        if (_image->bits_per_pixel == 32){
          long ptr = (x+y*_w)*4;
          if (msb_flag){
            ((unsigned char*)_image->data)[ptr++] = (udat & 0xff000000)>>24;
            ((unsigned char*)_image->data)[ptr++] = (udat & 0xff0000)>>16;
            ((unsigned char*)_image->data)[ptr++] = (udat & 0xff00)>>8;
            ((unsigned char*)_image->data)[ptr] = (udat & 0xff);
          }else{
            ((unsigned char*)_image->data)[ptr++] = (udat & 0xff);
            ((unsigned char*)_image->data)[ptr++] = (udat & 0xff00)>>8;
            ((unsigned char*)_image->data)[ptr++] = (udat & 0xff0000)>>16;
            ((unsigned char*)_image->data)[ptr] = (udat & 0xff000000)>>24;
          }
        }else{
          long ptr = (x+y*_w)*3;
          if (msb_flag){
            ((unsigned char*)_image->data)[ptr++] = (udat & 0xff0000)>>16;
            ((unsigned char*)_image->data)[ptr++] = (udat & 0xff00)>>8;
            ((unsigned char*)_image->data)[ptr] = (udat & 0xff);
          }else{
            ((unsigned char*)_image->data)[ptr++] = (udat & 0xff);
            ((unsigned char*)_image->data)[ptr++] = (udat & 0xff00)>>8;
            ((unsigned char*)_image->data)[ptr] = (udat & 0xff0000)>>16;
          }
        }
      }
    }else
    if (_bit > 8){
      udat = 0;
      if (red_shift >= 0){
        udat |= (((int)r << red_shift) & red_mask);
      }else{
        udat |= (((int)r >> (-red_shift)) & red_mask);
      }
      if (green_shift >= 0){
        udat |= (((int)g << green_shift) & green_mask);
      }else{
        udat |= (((int)g >> (-green_shift)) & green_mask);
      }
      if (blue_shift >= 0){
        udat |= (((int)b << blue_shift) & blue_mask);
      }else{
        udat |= (((int)b >> (-blue_shift)) & blue_mask);
      }
      long ptr = (x+y*_w)*2;
      if (msb_flag) {
        ((unsigned char*)_image->data)[ptr++] = (udat >> 8) & 0xff;
        ((unsigned char*)_image->data)[ptr] = (udat & 0xff);
      }else{
        ((unsigned char*)_image->data)[ptr++] = (udat & 0xff);
        ((unsigned char*)_image->data)[ptr] = (udat & 0xff00)>>8;
      }
    }else{
      XColor col;
      if (_display == NULL){
        _display = WSGIxwinAppDev()->display();
      }
      Colormap cm = DefaultColormap(_display,DefaultScreen(_display));
      if (r == 0xff){
        col.red = 0xffff;
      }else{
        col.red = r << 8;
      }
      if (g == 0xff){
        col.green = 0xffff;
      }else{
        col.green = g << 8;
      }
      if (b == 0xff){
        col.blue = 0xffff;
      }else{
        col.blue = b << 8;
      }
      XAllocColor(_display,cm,&col);
      _image->data[x+y*_w] =  col.pixel;
    }
    return WS_NO_ERR;
  }
  return WS_ERR;
}
long WSDxmwinDev::getBufferRGB(WSCushort x,WSCushort y, WSCuchar* r, WSCuchar* g,WSCuchar* b){
  if (mask_initialized == 0){
    mask_init();
  }
  if (_image == NULL){
    return WS_ERR;
  }
  if (x < _w && y < _h){
    WSCulong udat = 0;
    if (_bit > 16){
      if (_image->bits_per_pixel == 32){
        long ptr = (x+y*_w)*4;
        if (msb_flag){
          udat |= ((unsigned char*)_image->data)[ptr++]<<24;
          udat |= ((unsigned char*)_image->data)[ptr++]<<16;
          udat |= ((unsigned char*)_image->data)[ptr++]<<8;
          udat |= ((unsigned char*)_image->data)[ptr++];
        }else{
          udat |= ((unsigned char*)_image->data)[ptr++];
          udat |= ((unsigned char*)_image->data)[ptr++]<<8;
          udat |= ((unsigned char*)_image->data)[ptr++]<<16;
          udat |= ((unsigned char*)_image->data)[ptr++]<<24;
        }
        if (red_shift >= 0){
          *r = (udat & red_mask)>>red_shift;
        }else{
          *r = (udat & red_mask)<<(-red_shift);
        }
        if (green_shift >= 0){
          *g = (udat & green_mask)>>green_shift;
        }else{
          *g = (udat & green_mask)<<(-green_shift);
        }
        if (blue_shift >= 0){
          *b = (udat & blue_mask)>>blue_shift;
        }else{
          *b = (udat & blue_mask)<<(-blue_shift);
        }
      }else{
        long ptr = (x+y*_w)*3;
        if (msb_flag){
          udat |= ((unsigned char*)_image->data)[ptr++]<<16;
          udat |= ((unsigned char*)_image->data)[ptr++]<<8;
          udat |= ((unsigned char*)_image->data)[ptr++];
        }else{
          udat |= ((unsigned char*)_image->data)[ptr++];
          udat |= ((unsigned char*)_image->data)[ptr++]<<8;
          udat |= ((unsigned char*)_image->data)[ptr++]<<16;
        }
        if (red_shift >= 0){
          *r = (udat & red_mask)>>red_shift;
        }else{
          *r = (udat & red_mask)<<(-red_shift);
        }
        if (green_shift >= 0){
          *g = (udat & green_mask)>>green_shift;
        }else{
          *g = (udat & green_mask)<<(-green_shift);
        }
        if (blue_shift >= 0){
          *b = (udat & blue_mask)>>blue_shift;
        }else{
          *b = (udat & blue_mask)<<(-blue_shift);
        }
      }
    }else
    if (_bit > 8){
      long ptr = (x+y*_w)*2;
      if (msb_flag){
        udat |= ((unsigned char*)_image->data)[ptr++]<<8;
        udat |= ((unsigned char*)_image->data)[ptr++];
      }else{
        udat |= ((unsigned char*)_image->data)[ptr++];
        udat |= ((unsigned char*)_image->data)[ptr++]<<8;
      }
      if (red_shift >= 0){
        *r = (udat & red_mask)>>red_shift;
      }else{
        *r = (udat & red_mask)<<(-red_shift);
      }
      if (green_shift >= 0){
        *g = (udat & green_mask)>>green_shift;
      }else{
        *g = (udat & green_mask)<<(-green_shift);
      }
      if (blue_shift >= 0){
        *b = (udat & blue_mask)>>blue_shift;
      }else{
        *b = (udat & blue_mask)<<(-blue_shift);
      }
    }else{
      XColor col;
      if (_display == NULL){
        _display = WSGIxwinAppDev()->display();
      }
      col.pixel = _image->data[x+y*_w];
      Colormap cm = DefaultColormap(_display,DefaultScreen(_display));
      XQueryColor(_display,cm,&col);
      *r = col.red >>8;
      *g = col.green >>8;
      *b = col.blue >>8;
    }
  }
  return WS_ERR;
}
long WSDxmwinDev::putBufferToPixmap(){
  if (_image == NULL){
    return WS_ERR;
  }
  if (_pixmap == 0){
    return WS_ERR;
  }
  if (_pixmap_for_img != _pixmap){
    return WS_ERR;
  }
  Display* display = WSGIxwinAppDev()->display();
  XPutImage(display,_pixmap,_gc,_image,0,0,0,0,_w,_h);
                    
  return WS_NO_ERR;
}

long WSDxmwinDev::saveFile(char* fname,long type){
  if (_w == 0 || _h == 0){
    return WS_ERR;
  }
  
  static void* dl = NULL;
  static long dl_init = 0;
  static long (*fn)(FILE*,char*,long,long) = NULL;

  static void* dl_jpg = NULL;
  static long dl_init_jpg = 0;
  static long (*fn_jpg)(FILE*,char*,long,long) = NULL;

  if (type != WS_IMAGE_PNG && type != WS_IMAGE_JPG){
    return WSDmwindowDev::saveFile(fname,type);
  }

  if (dl_init == 0 && type == WS_IMAGE_PNG){
#ifndef MacOS
    dl = dlopen("png.so",RTLD_LAZY);
    if (dl == NULL){
      dl = dlopen("./png.so",RTLD_LAZY);
    }
#else //MacOS
    dl = dlopen("/usr/lib/png.bundle",RTLD_LAZY);
    if (dl == NULL){
      dl = dlopen("./png.bundle",RTLD_LAZY);
    }
#endif //MacOS
    if (dl == NULL){
#ifndef MacOS
WSMFtrace("ERROR. in WSDximage::initialize(). Library png.so open error. \nso, png image can not support...\n");
#else //MacOS
WSMFtrace("ERROR. in WSDximage::initialize(). Library png.bundle open error. \nso, png image can not support...\n");
#endif //MacOS
    }else{
      fn = (long (*)(FILE*,char*,long,long))dlsym(dl,"PngWriteBufToFp");
      if (fn == NULL){
WSMFtrace("ERROR. in WSDximage::initialize(). Library png.so is invalid. \nso, png image can not support...\n");
      }
    }
  }

//printf("fn=0x%x\n",fn);
  if (fn != NULL && type == WS_IMAGE_PNG){
    long ret = initBuffer();
    if (ret != WS_NO_ERR){
      return WS_ERR;
    }
    WSCuchar* buf = getBuffer();

    FILE* fp = fopen(fname,"w");
    if (fp != NULL){
      long ret = fn(fp,(char*)buf,_w,_h);
      if (ret != WS_NO_ERR){
        fclose(fp);
        return WS_ERR;
      }
      fclose(fp);
      return WS_NO_ERR;
    }
  }

  if (dl_init_jpg == 0 && type == WS_IMAGE_JPG){
#ifndef MacOS
    dl_jpg = dlopen("jpg.so",RTLD_LAZY);
    if (dl_jpg == NULL){
      dl_jpg = dlopen("./jpg.so",RTLD_LAZY);
    }
#else //MacOS
    dl_jpg = dlopen("/usr/lib/jpg.bundle",RTLD_LAZY);
    if (dl_jpg == NULL){
      dl_jpg = dlopen("./jpg.bundle",RTLD_LAZY);
    }
#endif //MacOS
    if (dl_jpg == NULL){
#ifndef MacOS
WSMFtrace("ERROR. in WSDximage::initialize(). Library jpg.so open error. \nso, jpeg image can not support...\n");
#else //MacOS
WSMFtrace("ERROR. in WSDximage::initialize(). Library jpg.bundle open error. \nso, jpeg image can not support...\n");
#endif //MacOS
    }else{
      fn_jpg = (long (*)(FILE*,char*,long,long))dlsym(dl_jpg,"JpegWriteBufToFp");
      if (fn_jpg == NULL){
WSMFtrace("ERROR. in WSDximage::initialize(). Library jpg.so is invalid. \nso, jpeg image can not support...\n");
      }
    }
  }
//printf("fn_jpg=0x%x\n",fn_jpg);
  if (fn_jpg != NULL && type == WS_IMAGE_JPG){
    long ret = initBuffer();
    if (ret != WS_NO_ERR){
      return WS_ERR;
    }
    WSCuchar* buf = getBuffer();

    FILE* fp = fopen(fname,"w");
    if (fp != NULL){
      long ret = fn_jpg(fp,(char*)buf,_w,_h);
      if (ret != WS_NO_ERR){
        fclose(fp);
        return WS_ERR;
      }
      fclose(fp);
      return WS_NO_ERR;
    }
  }

  return WS_ERR;
}

