//
// Copyright (C) 1999-2002 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 <assert.h>
#include <WSCbaseList.h>
#include <WSCbase.h>
#include <WSCdevice.h>
#include <WSCcolorSet.h>
#include <WSCfontSet.h>
#include <WSClocaleSet.h>
#include <nx/WSDnxAppDev.h>
#include <nx/WSDnxKeyboard.h>
#include <nx/WSDnxPrivateTimer.h>
#include <x11/WSDunixExecute.h>
#include <WSCinitializeManager.h>
#include <WSDmouse.h>
#include <WSDtimer.h>
#include <WSCdevice.h>
#include <nx/WSDnxSocket.h>
#include <WSDfile.h>
#include <nx/WSDnxFormDev.h>
#include <nx/WSnxcom.h>
#include <nx/WSDunixThread.h>

WSMFclassInit(WSDnxAppDev,WSDappDev);

WSDnxAppDev* WSGInxAppDev(){
dbprintf("WSGInxAppDev() %s:%d started.\n",__FILE__,__LINE__);
  WSDappDev* appdev = WSGIappDev();
  if (appdev == NULL){
    return NULL;
  }
  WSDnxAppDev* nxAppdev =(WSDnxAppDev*)appdev->cast("WSDnxAppDev");
  return nxAppdev;
}

WSDappDev* _nxAppDev_create_handler(){
dbprintf("_nxAppDev_create_handler %s:%d started.\n",__FILE__,__LINE__);
  return new WSDnxAppDev();
}

class _nxAppDev_init{
  public: _nxAppDev_init(){
dbprintf("_nxAppDev_init %s:%d started.\n",__FILE__,__LINE__);
    WSDappDev::setCreateInstanceHandler(_nxAppDev_create_handler);
  };
};

_nxAppDev_init _nxAppDev_init_run_constructor;

void WSGFdeviceInitialize(){
dbprintf("WSGFdeviceInitialize.. started..\n");
  static WSCbool initialized = False;
  if (initialized == False){
extern WSDfile* _unix_fp_chandler();
    WSDfile::setCreateInstanceHandler((void*)_unix_fp_chandler);
//extern WSDdragDrop* _xdrag_drop_create_handler_();
//    WSDdragDrop::setCreateHandler(_xdrag_drop_create_handler_);
//extern WSDmessage* _xclient_msg_create();
//    WSDmessage::setCreateHandler(_xclient_msg_create);
extern WSDmouse* _nxMouse_create_handler();
    WSDmouse::setCreateInstanceHandler(_nxMouse_create_handler);
extern WSDprivateTimer* _nxPrivatetimer_create();
    WSDprivateTimer::setCreateInstanceHandler((void*)_nxPrivatetimer_create);
extern WSDsocket* _nxSocket_create_handler();
    WSDsocket::setCreateHandler(_nxSocket_create_handler);
extern WSDtimer* _nxTimer_create_handler();
    WSDtimer::setCreateInstanceHandler(_nxTimer_create_handler);

extern WSDdev* _wsdnxFormdev_init_();
    WSGIappDevice()->setCreateHandler("formDev",_wsdnxFormdev_init_);
extern WSDdev* _wsdnxWindev_init_();
    WSGIappDevice()->setCreateHandler("windowDev",_wsdnxWindev_init_);
extern WSDdev* _wsdnxNwdev_init_();
    WSGIappDevice()->setCreateHandler("nwDev",_wsdnxNwdev_init_);
extern WSDdev* _wsdnxScrdev_init_();
    WSGIappDevice()->setCreateHandler("scrFrameDev",_wsdnxScrdev_init_);
extern WSDdev* _wsdnxmwindev_init_();
    WSGIappDevice()->setCreateHandler("mwindowDev",_wsdnxmwindev_init_);

extern WSDkeyboard* _nxKeyboard_create_handler();
    WSDkeyboard::setCreateInstanceHandler(_nxKeyboard_create_handler);

    WSDappDev::setCreateInstanceHandler(_nxAppDev_create_handler);
extern WSDcodeConvert* _code_convert_create_handler_();
    WSDcodeConvert::_set_code_convert_handler(_code_convert_create_handler_);
    WSGIappCodeConvert()->initialize();
    initialized = True;
extern void _nxFont_init();
    _nxFont_init();
extern void _nxColor_init();
    _nxColor_init();
extern void _nxImage_init();
    _nxImage_init();
    WSGIappInitializeManager()->execInitializeProcs();
  }
dbprintf("WSGFdeviceInitialize.. done..\n");
}
WSDnxAppDev::WSDnxAppDev(){
  _have_color_map = False;
  _color_map = NULL;
}
WSDnxAppDev::~WSDnxAppDev(){}

WSCushort WSDnxAppDev::getWidth(){
  // TODO get screen size 
  return 1024;

}
WSCushort WSDnxAppDev::getHeight(){
  // TODO get screen size 
  return 768;
}

long WSDnxAppDev::getDeviceResource(){
  return 0;
}

long WSDnxAppDev::getWindowResource(){
  return 0;
}

long WSDnxAppDev::getContextResource(){
  return 0;
}

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

long WSDnxAppDev::setInitPrm(int iprm,char** cprm){
   _iprm = iprm;
   _cprm = cprm;
   return WS_NO_ERR;
}
long is_own_window(void* w){
  // TODO check window whether it is mine.
  return True;
}
long WSDnxAppDev::loadGuiPolicy(){
  WSCstring* envstr = WSGFreadTextFile("$(HOME)/.wsrc");
  if (envstr != NULL){
    while(envstr->eof() == False){
      WSCstring index = envstr->gets();
      WSCstring data = envstr->gets();
      WSCstring data2;
      data2 = data;
      index.delHeadSpace();
      index.delTailSpace();
      index.delLineFeed();
      data.delHeadSpace();
      data.delTailSpace();
      data.delLineFeed();
      if (!strcmp((char*)index,"#POLICY") && strcmp((char*)data,"")){
        long val = atoi((char*)data);
        if (_policy == -1){
          setGuiPolicy(val,False);
        }
      }else
      if (!strcmp((char*)index,"#TOPSHADOWCOLOR") && strcmp((char*)data,"")){
        short cno = WSGIappColorSet()->getColorNo((char*)data);
        WSGIappColorSet()->setDefaultColorNo(WS_DF_TOPSHADOWCOLOR,cno);
      }else
      if (!strcmp((char*)index,"#BOTTOMSHADOWCOLOR") && strcmp((char*)data,"")){
        short cno = WSGIappColorSet()->getColorNo((char*)data);
        WSGIappColorSet()->setDefaultColorNo(WS_DF_BOTTOMSHADOWCOLOR,cno);
      }else
      if (!strcmp((char*)index,"#BACKCOLOR") && strcmp((char*)data,"")){
        short cno = WSGIappColorSet()->getColorNo((char*)data);
        WSGIappColorSet()->setDefaultColorNo(WS_DF_BACKCOLOR,cno);
      }else
      if (!strcmp((char*)index,"#FORECOLOR") && strcmp((char*)data,"")){
        short cno = WSGIappColorSet()->getColorNo((char*)data);
        WSGIappColorSet()->setDefaultColorNo(WS_DF_FORECOLOR,cno);
      }else
      if (!strcmp((char*)index,"#MENUFORECOLOR") && strcmp((char*)data,"")){
        short cno = WSGIappColorSet()->getColorNo((char*)data);
        WSGIappColorSet()->setDefaultColorNo(WS_DF_MENUFORECOLOR,cno);
      }else
      if (!strcmp((char*)index,"#MENUBACKCOLOR") && strcmp((char*)data,"")){
        short cno = WSGIappColorSet()->getColorNo((char*)data);
        WSGIappColorSet()->setDefaultColorNo(WS_DF_MENUBACKCOLOR,cno);
      }else
      if (!strcmp((char*)index,"#MENUSELECTCOLOR") && strcmp((char*)data,"")){
        short cno = WSGIappColorSet()->getColorNo((char*)data);
        WSGIappColorSet()->setDefaultColorNo(WS_DF_MENUSELECTCOLOR,cno);
      }else
      if (!strcmp((char*)index,"#MENUTOPSHADOWCOLOR") && strcmp((char*)data,"")){
        short cno = WSGIappColorSet()->getColorNo((char*)data);
        WSGIappColorSet()->setDefaultColorNo(WS_DF_MENUTOPSHADOWCOLOR,cno);
      }else
      if (!strcmp((char*)index,"#MENUBOTTOMSHADOWCOLOR") && strcmp((char*)data,"")){
        short cno = WSGIappColorSet()->getColorNo((char*)data);
        WSGIappColorSet()->setDefaultColorNo(WS_DF_MENUBOTTOMSHADOWCOLOR,cno);
      }else
      if (!strcmp((char*)index,"#WORKBACKCOLOR") && strcmp((char*)data,"")){
        short cno = WSGIappColorSet()->getColorNo((char*)data);
        WSGIappColorSet()->setDefaultColorNo(WS_DF_WORKBACKCOLOR,cno);
      }else
      if (!strcmp((char*)index,"#DARKBACKCOLOR") && strcmp((char*)data,"")){
        short cno = WSGIappColorSet()->getColorNo((char*)data);
        WSGIappColorSet()->setDefaultColorNo(WS_DF_DARKBACKCOLOR,cno);
      }else
      if (!strcmp((char*)index,"#BARSHADOWCOLOR") && strcmp((char*)data,"")){
        short cno = WSGIappColorSet()->getColorNo((char*)data);
        WSGIappColorSet()->setDefaultColorNo(WS_DF_BARSHADOWCOLOR,cno);
      }else
      if (!strcmp((char*)index,"#NWTOPSHADOWCOLOR") && strcmp((char*)data,"")){
        short cno = WSGIappColorSet()->getColorNo((char*)data);
        WSGIappColorSet()->setDefaultColorNo(WS_DF_NWTOPSHADOWCOLOR,cno);
      }else
      if (!strcmp((char*)index,"#NWBOTTOMSHADOWCOLOR") && strcmp((char*)data,"")){
        short cno = WSGIappColorSet()->getColorNo((char*)data);
        WSGIappColorSet()->setDefaultColorNo(WS_DF_NWBOTTOMSHADOWCOLOR,cno);
      }else
      if (!strcmp((char*)index,"#NWBACKCOLOR") && strcmp((char*)data,"")){
        short cno = WSGIappColorSet()->getColorNo((char*)data);
        WSGIappColorSet()->setDefaultColorNo(WS_DF_NWBACKCOLOR,cno);
      }else
      if (!strcmp((char*)index,"#NWFORECOLOR") && strcmp((char*)data,"")){
        short cno = WSGIappColorSet()->getColorNo((char*)data);
        WSGIappColorSet()->setDefaultColorNo(WS_DF_NWFORECOLOR,cno);
      }else
      if (!strcmp((char*)index,"#DARKBOTTOMSHADOWCOLOR") && strcmp((char*)data,"")){
        short cno = WSGIappColorSet()->getColorNo((char*)data);
        WSGIappColorSet()->setDefaultColorNo(WS_DF_DARKBOTTOMSHADOWCOLOR,cno);
      }else
      if (!strcmp((char*)index,"#MENUSELECTFORECOLOR") && strcmp((char*)data,"")){
        short cno = WSGIappColorSet()->getColorNo((char*)data);
        WSGIappColorSet()->setDefaultColorNo(WS_DF_MENUSELECTFORECOLOR,cno);
      }else
      if (!strcmp((char*)index,"#AQUAFORECOLOR") && strcmp((char*)data,"")){
        short cno = WSGIappColorSet()->getColorNo((char*)data);
        WSGIappColorSet()->setDefaultColorNo(WS_DF_AQUAFORECOLOR,cno);
      }else
      if (!strcmp((char*)index,"#AQUAHIGHLIGHTCOLOR") && strcmp((char*)data,"")){
        short cno = WSGIappColorSet()->getColorNo((char*)data);
        WSGIappColorSet()->setDefaultColorNo(WS_DF_AQUAHIGHLIGHTCOLOR,cno);
      }else
      if (!strcmp((char*)index,"#DEFAULTFONT") && strcmp((char*)data2,"")){
        WSDfont* font = WSGIappFontSet()->getFont(8);
        font->setFontName(data2);
      }
    }
    if (_policy == -1){
      _policy = WS_POLICY_WINDOWS;
    }
    delete envstr;
    return WS_NO_ERR;
  }
  return WS_ERR;
}
long WSDnxAppDev::saveGuiPolicy(){
  WSCstring str;
  str << "#POLICY\n";
  str << getGuiPolicy() << "\n";
  str << "#TOPSHADOWCOLOR\n";
  str << WSGIappColorSet()->getColor(WS_DF_TOPSHADOWCOLOR)->getSrc() << "\n";
  str << "#BOTTOMSHADOWCOLOR\n";
  str << WSGIappColorSet()->getColor(WS_DF_BOTTOMSHADOWCOLOR)->getSrc() << "\n";
  str << "#BACKCOLOR\n";
  str << WSGIappColorSet()->getColor(WS_DF_BACKCOLOR)->getSrc() << "\n";
  str << "#FORECOLOR\n";
  str << WSGIappColorSet()->getColor(WS_DF_FORECOLOR)->getSrc() << "\n";
  str << "#MENUFORECOLOR\n";
  str << WSGIappColorSet()->getColor(WS_DF_MENUFORECOLOR)->getSrc() << "\n";
  str << "#MENUBACKCOLOR\n";
  str << WSGIappColorSet()->getColor(WS_DF_MENUBACKCOLOR)->getSrc() << "\n";
  str << "#MENUSELECTCOLOR\n";
  str << WSGIappColorSet()->getColor(WS_DF_MENUSELECTCOLOR)->getSrc() << "\n";
  str << "#MENUSELECTFORECOLOR\n";
  str << WSGIappColorSet()->getColor(WS_DF_MENUSELECTFORECOLOR)->getSrc() << "\n";
  str << "#MENUTOPSHADOWCOLOR\n";
  str << WSGIappColorSet()->getColor(WS_DF_MENUTOPSHADOWCOLOR)->getSrc() << "\n";
  str << "#MENUBOTTOMSHADOWCOLOR\n";
  str << WSGIappColorSet()->getColor(WS_DF_MENUBOTTOMSHADOWCOLOR)->getSrc() << "\n";
  str << "#WORKBACKCOLOR\n";
  str << WSGIappColorSet()->getColor(WS_DF_WORKBACKCOLOR)->getSrc() << "\n";
  str << "#DARKBACKCOLOR\n";
  str << WSGIappColorSet()->getColor(WS_DF_DARKBACKCOLOR)->getSrc() << "\n";
  str << "#BARSHADOWCOLOR\n";
  str << WSGIappColorSet()->getColor(WS_DF_BARSHADOWCOLOR)->getSrc() << "\n";
  str << "#NWTOPSHADOWCOLOR\n";
  str << WSGIappColorSet()->getColor(WS_DF_NWTOPSHADOWCOLOR)->getSrc() << "\n";
  str << "#NWBOTTOMSHADOWCOLOR\n";
  str << WSGIappColorSet()->getColor(WS_DF_NWBOTTOMSHADOWCOLOR)->getSrc() << "\n";
  str << "#NWBACKCOLOR\n";
  str << WSGIappColorSet()->getColor(WS_DF_NWBACKCOLOR)->getSrc() << "\n";
  str << "#NWFORECOLOR\n";
  str << WSGIappColorSet()->getColor(WS_DF_NWFORECOLOR)->getSrc() << "\n";
  str << "#DARKBOTTOMSHADOWCOLOR\n";
  str << WSGIappColorSet()->getColor(WS_DF_DARKBOTTOMSHADOWCOLOR)->getSrc() << "\n";
  str << "#AQUAHIGHLIGHTCOLOR\n";
  str << WSGIappColorSet()->getColor(WS_DF_AQUAHIGHLIGHTCOLOR)->getSrc() << "\n";
  str << "#AQUAFORECOLOR\n";
  str << WSGIappColorSet()->getColor(WS_DF_AQUAFORECOLOR)->getSrc() << "\n";
  str << "#DEFAULTFONT\n";
  str << WSGIappFontSet()->getDefaultFont()->getFontName() << "\n";

  return WSGFreplaceTextFile("$(HOME)/.wsrc",str,False);
}

long WSDnxAppDev::initialize(){
  WSDappDev::initialize();


  short cno;

  cno = WSGIappColorSet()->getColorNo("gray85");
  WSGIappColorSet()->setDefaultColorNo(WS_DF_BACKCOLOR,cno);

  cno = WSGIappColorSet()->getColorNo("black");
  WSGIappColorSet()->setDefaultColorNo(WS_DF_FORECOLOR,cno);

  cno = WSGIappColorSet()->getColorNo("gray95");
  WSGIappColorSet()->setDefaultColorNo(WS_DF_TOPSHADOWCOLOR,cno);

  cno = WSGIappColorSet()->getColorNo("gray55");
  WSGIappColorSet()->setDefaultColorNo(WS_DF_BOTTOMSHADOWCOLOR,cno);

  cno = WSGIappColorSet()->getColorNo("black");
  WSGIappColorSet()->setDefaultColorNo(WS_DF_MENUFORECOLOR,cno);

  cno = WSGIappColorSet()->getColorNo("white");
  WSGIappColorSet()->setDefaultColorNo(WS_DF_MENUSELECTFORECOLOR,cno);

  cno = WSGIappColorSet()->getColorNo("gray80");
  WSGIappColorSet()->setDefaultColorNo(WS_DF_MENUBACKCOLOR,cno);

  cno = WSGIappColorSet()->getColorNo("slategray4");
  WSGIappColorSet()->setDefaultColorNo(WS_DF_MENUSELECTCOLOR,cno);


  cno = WSGIappColorSet()->getColorNo("gray95");
  WSGIappColorSet()->setDefaultColorNo(WS_DF_MENUTOPSHADOWCOLOR,cno);

  cno = WSGIappColorSet()->getColorNo("gray55");
  WSGIappColorSet()->setDefaultColorNo(WS_DF_MENUBOTTOMSHADOWCOLOR,cno);

  cno = WSGIappColorSet()->getColorNo("gray80");
  WSGIappColorSet()->setDefaultColorNo(WS_DF_DARKBACKCOLOR,cno);

  cno = WSGIappColorSet()->getColorNo("white");
  WSGIappColorSet()->setDefaultColorNo(WS_DF_WORKBACKCOLOR,cno);

  cno = WSGIappColorSet()->getColorNo("gray80");
  WSGIappColorSet()->setDefaultColorNo(WS_DF_BARSHADOWCOLOR,cno);

  cno = WSGIappColorSet()->getColorNo("gray85");
  WSGIappColorSet()->setDefaultColorNo(WS_DF_NWBACKCOLOR,cno);

  cno = WSGIappColorSet()->getColorNo("black");
  WSGIappColorSet()->setDefaultColorNo(WS_DF_NWFORECOLOR,cno);
  WSGIappColorSet()->setDefaultColorNo(WS_DF_DARKBOTTOMSHADOWCOLOR,cno);

  cno = WSGIappColorSet()->getColorNo("gray95");
  WSGIappColorSet()->setDefaultColorNo(WS_DF_NWTOPSHADOWCOLOR,cno);

  cno = WSGIappColorSet()->getColorNo("gray55");
  WSGIappColorSet()->setDefaultColorNo(WS_DF_NWBOTTOMSHADOWCOLOR,cno);

  cno = WSGIappColorSet()->getColorNo("#e0e0ff");
  WSGIappColorSet()->setDefaultColorNo(WS_DF_AQUAFORECOLOR,cno);

  cno = WSGIappColorSet()->getColorNo("#d0d0ff");
  WSGIappColorSet()->setDefaultColorNo(WS_DF_AQUAHIGHLIGHTCOLOR,cno);

  loadGuiPolicy();

  // TODO initialize the event loop.

#ifdef WS_OWN_EVENT_LOOP
  WSGFnxInitializeEventLoop();
#endif //WS_OWN_EVENT_LOOP

  return WS_NO_ERR;
}

long WSDnxAppDev::handleEvents(){
  WSGIappDevice()->clearDeleteList();
  WSGIappObjectList()->execInitialize();
  WSGIappObjectList()->execUpdate();

  while(1){
//printf("WSDnxAppDev::handleEvents start dispatchEvent().   XXXXXXXX\n");
dbprintf("WSDnxAppDev::handleEvents start dispatchEvent().   XXXXXXXX\n");
    dispatchEvent();
dbprintf("WSDnxAppDev::handleEvents start clearDeleteList(). XXXXXXXX\n");
    WSGIappDevice()->clearDeleteList();
  }
  return WS_NO_ERR;
}
long WSDnxAppDev::dispatchEvent(){
  return _dispatchEvent(True);
}
long WSDnxAppDev::processEvent(){
  return _dispatchEvent(False);
}

void _exec_resize(void* window,WSCrect* r){
  if (is_own_window(window) == False){
    return;
  }
  WSDnxFormDev* dev = NULL;
  // TODO get this pointer from window..

  if (dev == NULL){
dbprintf("_resize(W=0x%x) has no instance.\n",window);
    return;
  }
  dev->_evh_resize(r);
} 
void _destroy_evt(void* window,void* ev){
  if (is_own_window(window) == False){
    return;
  }

  WSDnxFormDev* dev;
  // TODO get this pointer from window.

  if (dev == NULL){
dbprintf("_destroy_evt(W=0x%x) has no instance.\n",window);
    return;
  }
  dev->_evh_destroy(ev);
}

void _expose(void* window){
  if (is_own_window(window) == False){
    return;
  }
  WSDnxFormDev* dev = NULL;
  // TODO get this pointer from window.

  if (dev == NULL){
dbprintf("_expose(W=0x%x) has no instance.\n",window);
    return;
  }

  WSCrect r;
  // TODO get clip list from window and set it to
  //      the cliplist of dev->getClipList()
  WSCrectList* clip_list = dev->getClipList();

  // TODO get clip list num from window and set it with dev->setClipNum()
  long nr = 0;
  dev->setClipNum(nr);

  // TODO get exposed area list "rlist" and set it to "r"
  r.x = 0;
  r.y = 0;
  r.width = 0;
  r.height = 0;

  dev->_evh_expose(&r);
}
//static WSDnxFormDev* grab_dev = NULL;
void _btn_press(void* window,void* ev){
  if (is_own_window(window) == False){
    return;
  }
  WSDnxFormDev* dev = NULL;
  // TODO get this pointer from window.

  if (dev != NULL){
    // TODO get mouse point from ev
    short x = 0;
    short y = 0;
    dev = dev->getChildWithPoint(x,y);
  }
  if (dev == NULL){
dbprintf("_btn_press(W=0x%x) has no instance.\n",window);
    return;
  }
  dev->_evh_btn_press(ev);
}

void _mouse_move(void* window,void* ev){
  if (is_own_window(window) == False){
    return;
  }
  WSDnxFormDev* dev = NULL;
  // TODO get this pointer from window.

  if (dev != NULL){
    // TODO get mouse point from ev
    short x = 0;
    short y = 0;
    dev = dev->getChildWithPoint(x,y);
  }
  if (dev == NULL){
dbprintf("_btn_press(W=0x%x) has no instance.\n",window);
    return;
  }
  dev->_evh_mouse_move(ev);
}


void _btn_release(void* window,void* ev){
  WSDnxFormDev* dev = NULL;
  WSDnxFormDev* tdev = WSGInxAppDev()->getBtnPressGrabTarget();
  if (tdev == NULL ||
      WSDnxFormDev::isValidInstance(tdev) == False){
    WSGInxAppDev()->setBtnPressGrabTarget(NULL);
    if (is_own_window(window) == False){
      return;
    }
    // TODO get this pointer from window..

    if (dev != NULL){
      // TODO get mouse point from ev
      short x = 0;
      short y = 0;
      dev = dev->getChildWithPoint(x,y);
    }
    if (dev == NULL){
dbprintf("_btn_release(W=0x%x) has no instance.\n",window);
      return;
    }
  }else{
    dev = tdev;
  } 
dbprintf("_evh_release(W=0x%x) start.\n",window);
  dev->_evh_btn_release(ev);
}

static WSDnxFormDev* _mouse_target = NULL;
static WSDnxFormDev* _mouse_grab_target = NULL;
static WSDnxFormDev* _mouse_btn_grab_target = NULL;
static WSCbool _mouse_grabbed = False;
static WSCbool _mouse_btn_grabbed = False;

WSDnxFormDev* WSDnxAppDev::getGrabTarget(){
  if (_mouse_grabbed != False){
    return _mouse_grab_target;
  }
  return NULL;
}
WSDnxFormDev* WSDnxAppDev::getBtnPressGrabTarget(){
  if (_mouse_btn_grabbed != False){
    return _mouse_btn_grab_target;
  }
  return NULL;
}
void WSDnxAppDev::setGrabTarget(WSDnxFormDev* dev){
  if (dev == NULL){
    _mouse_grabbed = False;
    _mouse_grab_target = NULL;
    return;
  }
  _mouse_grab_target = dev;
  _mouse_grabbed = True;
}
WSCbool WSDnxAppDev::getMouseGrabbed(){
  if ( _mouse_grabbed != False ||
       _mouse_btn_grabbed != False){
    return True;
  }
  return False;
}
void WSDnxAppDev::setBtnPressGrabTarget(WSDnxFormDev* dev){
  if (dev == NULL){
    _mouse_btn_grabbed = False;
    _mouse_btn_grab_target = NULL;
    return;
  }
  _mouse_btn_grab_target = dev;
  _mouse_btn_grabbed = True;
}
void recvmsg(){
  char buffer[128];
  // TODO receive from message from timer/socket

  // socket accept..
  //  _accept_send_type* data = NULL;
  //  memcpy(&data,msg->msg_body.ANYMSG.msg_str,sizeof(data));
  //  void(*hd)(WSDsocket*,void*,WSCulong) = data->hd;
  //  if (hd != NULL){
  //    hd(data->sock,(void*)data->socket,data->addr);
  //  }
  //  delete data;

  // timer callback..
  //  WSDnxPrivateTimer* timer = NULL;
  //  W tid = 0;
  //  memcpy(&timer,msg->msg_body.ANYMSG.msg_str,sizeof(W));
  //  memcpy(&tid,&msg->msg_body.ANYMSG.msg_str[sizeof(W)],sizeof(W));
  //  if (WSDnxPrivateTimer::isValid(timer)){
  //    timer->_timer_callback(tid);
  //  }

  // execute callback..
  //  memcpy(&data,msg->msg_body.ANYMSG.msg_str,sizeof(data));
  //  WSDnxExecute* obj = data.obj;
  //  if (obj->getId() == data.id){
  //    WSDnxExecute::_callback(obj);
  //  }
}

long WSDnxAppDev::_dispatchEvent(WSCbool wait){
  // TODO get next window event
#ifdef WS_OWN_EVENT_LOOP
  WSDnxEvent ev;
  WSCbool fl = WSGFnxGetNextEvent(&ev,wait);
  if (fl == True){
    switch(ev.type){
      case WSEV_NX_TIMER:{
        _timer_send_type* data = (_timer_send_type*)ev.data;
        WSDnxPrivateTimer* timer = data->timer;
        WSCulong tid = data->tid;
        if (WSDnxPrivateTimer::isValid(timer)){
          timer->_timer_callback(tid);
        }
        delete data;
        break;
      }
      case WSEV_NX_ACCEPT:{
        _accept_send_type* data = (_accept_send_type*)ev.data;
        void(*hd)(WSDsocket*,void*,WSCulong) = data->hd;
        if (hd != NULL){
          hd(data->sock,(void*)data->socket,data->addr);
        }
        delete data;
        break;
      }
      case WSEV_NX_THREAD_MESSAGE:{
        WSDunixThread* ptr = (WSDunixThread*)ev.data;
        void(*fn)(WSDunixThread*,void*) =
             (void(*)(WSDunixThread*,void*))ptr->getCallbackFunction();
        if (fn != NULL){
          fn(ptr,ptr->getCallbackData());
        }
        break;
      }
    }
    WSGIappObjectList()->execInitialize();
    WSGIappObjectList()->execUpdate();
  }
#endif //WS_OWN_EVENT_LOOP

  // TODO other message received.
  //
  //    recvmsg();
  //    WSDnxFormDev::executeUpdate();
  //    WSGIappObjectList()->execInitialize();
  //    WSGIappObjectList()->execUpdate();
  //    return WS_NO_ERR;

  // TODO exposed..
  //    _expose(window);
  //    WSDnxFormDev::executeUpdate();
  //    WSGIappObjectList()->execInitialize();
  //    WSGIappObjectList()->execUpdate();
  //    return WS_NO_ERR;

  // TODO mouse pressed
  //    WSDnxFormDev* mouse_target = _mouse_grab_target;
  //    if (mouse_target != NULL &&
  //        WSDnxFormDev::isValidInstance(mouse_target) == False){
  //      mouse_target = NULL;
  //    }
  //    if (mouse_target != NULL){
  //      mouse_target->_evh_btn_press(&ev);
  //    }else{
  //      _btn_press(window,&ev);
  //    }
  //    WSDnxFormDev::executeUpdate();
  //    WSGIappObjectList()->execInitialize();
  //    WSGIappObjectList()->execUpdate();
  //    return WS_NO_ERR;

  // TODO mouse release
  //    WSDnxFormDev* mouse_target = _mouse_target;
  //    if (_mouse_btn_grab_target != NULL){
  //      mouse_target = _mouse_btn_grab_target;
  //    }
  //    if (_mouse_grab_target != NULL){
  //      mouse_target = _mouse_grab_target;
  //    }
  //    if (mouse_target != NULL &&
  //        WSDnxFormDev::isValidInstance(mouse_target) == False){
  //      mouse_target = NULL;
  //    }
  //    if (mouse_target != NULL){
  //      mouse_target->_evh_btn_release(&ev);
  //    }else{
  //      _btn_release(ev.s.wid,&ev);
  //    }
  //    WSDnxFormDev::executeUpdate();
  //    WSGIappObjectList()->execInitialize();
  //    WSGIappObjectList()->execUpdate();
  //    return WS_NO_ERR;


  // TODO mouse moved
  //    WSDnxFormDev* mouse_target = _mouse_target;
  //    if (_mouse_btn_grab_target != NULL){
  //      mouse_target = _mouse_btn_grab_target;
  //    }
  //    if (_mouse_grab_target != NULL){
  //      mouse_target = _mouse_grab_target;
  //    }
  //    if (mouse_target != NULL &&
  //        WSDnxFormDev::isValidInstance(mouse_target) == False){
  //      mouse_target = NULL;
  //    }
  //    if (mouse_target != NULL){
  //      mouse_target->_evh_mouse_move(&ev);
  //    }else{
  //      _mouse_move(ev.s.wid,&ev);
  //    }
  //    WSDnxFormDev::executeUpdate();
  //    WSGIappObjectList()->execInitialize();
  //    WSGIappObjectList()->execUpdate();
  //    return WS_NO_ERR;


  // TODO window resized
  //    _exec_resize(ev.s.wid,&rect);
  //    _expose(ev.s.wid);
  //    WSDnxFormDev::executeUpdate();
  //    WSGIappObjectList()->execInitialize();
  //    WSGIappObjectList()->execUpdate();
  //    return WS_NO_ERR;

  // TODO window destroyed
  //    _destroy_evt(window,&ev);
  //    WSDnxFormDev::executeUpdate();
  //    WSGIappObjectList()->execInitialize();
  //    WSGIappObjectList()->execUpdate();
  //    return WS_NO_ERR;


  // TODO key pressed
  //    WSGInxKeyboard()->deliverKeyEvent(&ev,True);
  //    WSDnxFormDev::executeUpdate();
  //    WSGIappObjectList()->execInitialize();
  //    WSGIappObjectList()->execUpdate();
  //    return WS_NO_ERR;

  // TODO key released
  //    WSGInxKeyboard()->deliverKeyEvent(&ev,False);
  //    WSDnxFormDev::executeUpdate();
  //    WSGIappObjectList()->execInitialize();
  //    WSGIappObjectList()->execUpdate();
  //    return WS_NO_ERR;

  return WS_ERR;
}

void WSDnxAppDev::update(){
}

WSCbool WSDnxAppDev::haveColorMap(){
  return _have_color_map;
}
void* WSDnxAppDev::getNewMemContext(WSCulong w,WSCulong h){
  // TODO create new mem context..
  return NULL;
}
void WSDnxAppDev::destroyMemContext(void* mem_context){
  // TODO destroy mem_context.
}
void* WSDnxAppDev::getActiveWindow(){
  // TODO getActiveWindow.
  return NULL;
}
