//
// 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/WSDxscrFrameDev.h>
#include <x11/WSDxappDev.h>
#include <x11/WSDxdraw.h>
#include <x11/WSxcom.h>
#include <WSCdevice.h>
#include <WSCcolorSet.h>
#include <X11/StringDefs.h>
#include <form.h>
#include <WSCbase.h>


WSMFclassInit(WSDxscrFrameDev,WSDxformDev);
WSDdev* _wsdxscrdev_init_(){
  return new WSDxscrFrameDev();
}

class _WSDxscrFrameDev_init_ {
  public:_WSDxscrFrameDev_init_(){
     WSGIappDevice()->setCreateHandler("scrFrameDev",_wsdxscrdev_init_);
  };
};
static _WSDxscrFrameDev_init_ _init_to_run_WSDxscrFrameDev_;

WSDxscrFrameDev::WSDxscrFrameDev(){
  _scr_form = 0;
  _work_width =0;
  _work_height =0;
  _title_height = 0;
}

WSDxscrFrameDev::~WSDxscrFrameDev(){
  destroyWindow();
}

long WSDxscrFrameDev::setValue(long kind,void* data){
  char psbk = getPixmapStyle();
  setPixmapStyle( WS_DIRECT_WINDOW);
  WSDwindowDev::setValue(kind,data);
  setPixmapStyle(psbk);

  Arg args[5];
  long vl;
  WSDcolor* color;
  char fl;
  switch(kind){
    case WSDEV_X: 
	         if (_scr_form != NULL){
               if (getVisible() == True){
                 WSDxformDev* pdev = getParentAreaDev();
                 if (pdev != NULL && (pdev->getWidth() < *(short*)data + _w_w ||
                                       pdev->getHeight() < _w_y +_w_h )){
                   XtUnmanageChild((Widget)_scr_form);
                 }
               }
  
               XtSetArg(args[0],XtNx,*(short*)data);
               XtSetValues((Widget)_scr_form,args,1);
               if (getVisible() == True){
                 XtManageChild((Widget)_scr_form);
               }
             }
             break;
    case WSDEV_Y:
	         if (_scr_form != NULL){
               if (getVisible() == True){
                 WSDxformDev* pdev = getParentAreaDev();
                 if (pdev != NULL &&(pdev->getHeight() < *(short*)data + _w_h ||
                                       pdev->getWidth()  < _w_x + _w_w)){
                   XtUnmanageChild((Widget)_scr_form);
                 }
               }
               XtSetArg(args[0],XtNy,*(short*)data);
               XtSetValues((Widget)_scr_form,args,1);
               if (getVisible() == True){
                 XtManageChild((Widget)_scr_form);
               }
             }
             break;
    case WSDEV_WIDTH:
	         if (_scr_form != NULL && *(WSCushort*)data > 0){
               XtSetArg(args[0],XtNwidth,*(WSCushort*)data);
               XtSetValues((Widget)_scr_form,args,1);
			 }
             break;
    case WSDEV_HEIGHT:
	         if (_scr_form != NULL && *(WSCushort*)data > 0){
               XtSetArg(args[0],XtNheight,*(WSCushort*)data);
               XtSetValues((Widget)_scr_form,args,1);
			 }
             break;
    case WSDEV_BACKCOLOR:
	         if (_widget != NULL){
               _bg = *(short*)data;
               color = WSGIappColorSet()->getColor(*(short*)data);
               if (color != NULL){
                 XtSetArg(args[0],XtNbackground,color->getValue1());
                 XtSetValues((Widget)_widget,args,1);
                 XtSetValues((Widget)_scr_form,args,1);
               }
             }
             break;
    case WSDEV_WORK_X:
             vl = *(WSCushort*)data;
             if (vl > _work_width - _w_w){
               vl = _work_width - _w_w;
               if (vl < 0){
                 vl = 0;
               }
             }
             _h_scr_pos = vl;
             if (_addr_change_handler != NULL){
               _addr_change_handler(this,_handler_data);
             }

             if (_widget != NULL){
               XtSetArg(args[0],XtNx,-_h_scr_pos);
               XtSetValues(_widget,args,1);
             }
             break;
    case WSDEV_WORK_Y:
             vl = *(WSCushort*)data;
             if (vl > _work_height - _w_h){
               vl = _work_height - _w_h;
               if (vl < 0){
                 vl = 0;
               }
             }
             _v_scr_pos = vl;
             if (_addr_change_handler != NULL){
               _addr_change_handler(this,_handler_data);
             }
             if (_widget != NULL){
               XtSetArg(args[0],XtNy,-_v_scr_pos);
               XtSetValues(_widget,args,1);
             }
             break;
    case WSDEV_WORK_WIDTH:
             if (getPixmapStyle() != WS_DIRECT_WINDOW){
               if (_work_width < *(WSCushort*)data){ //scrform expose
                                                     //redraw bugfix
                 destroyPixmap();
               }
             }
             _work_width = *(WSCushort*)data;

             if (_widget != NULL){
               XtSetArg(args[0],XtNwidth,*(WSCushort*)data);
               XtSetValues((Widget)_widget,args,1);
             }
             if (_h_scr_pos > _work_width - _w_w){
               _h_scr_pos = _work_width - _w_w;
               if (_h_scr_pos < 0){
                 _h_scr_pos = 0;
               }
               if (_addr_change_handler != NULL){
                 _addr_change_handler(this,_handler_data);
               }
             }
             break;

    case WSDEV_WORK_HEIGHT:
             if (getPixmapStyle() != WS_DIRECT_WINDOW){
               if (_work_height < *(WSCushort*)data){//scrform expose
                                                     //redraw bugfix
                 destroyPixmap();
               }
             }
             _work_height = *(WSCushort*)data;

             if (_widget != NULL){
               XtSetArg(args[0],XtNheight,*(WSCushort*)data);
               XtSetValues((Widget)_widget,args,1);
             }
             if (_v_scr_pos > _work_height - _w_h){
               _v_scr_pos = _work_height - _w_h;
               if (_v_scr_pos < 0){
                 _v_scr_pos = 0;
               }
               if (_addr_change_handler != NULL){
                 _addr_change_handler(this,_handler_data);
               }
             }
             break;
    case WSDEV_PIXMAP_STYLE:
             fl = *(char*)data;
             setPixmapStyle(fl);
             destroyPixmap();
             break;
    case WSDEV_VHEAD_X:
             _p1_x = *(WSCushort*)data;
             break;
    case WSDEV_VHEAD_Y:
             _p1_y = *(WSCushort*)data;
             break;
    case WSDEV_VFOOT_X:
             _p2_x = *(WSCushort*)data;
             break;
    case WSDEV_VFOOT_Y:
             _p2_y = *(WSCushort*)data;
             break;
    case WSDEV_TITLE_HEIGHT:
             _title_height = *(WSCushort*)data;
             break;
    case WSDEV_GRAB_POINTER:
             if (_widget == NULL){
               break;
             }
             fl = *(WSCbool*)data;
             if (fl != False){
               XGrabPointer(XtDisplay(_widget),XtWindow(_widget),False,
                  ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
                  GrabModeAsync,GrabModeAsync,None,None,CurrentTime);
               XGrabKeyboard(XtDisplay(_widget),XtWindow(_widget),False,
                  GrabModeAsync,GrabModeAsync,CurrentTime);
             }else{
               XUngrabPointer(XtDisplay(_widget),CurrentTime);
               XUngrabKeyboard(XtDisplay(_widget),CurrentTime);
             }
             break;

    default:
      return WS_ERR;
  }
//  setPixmapStyle(psbk);
  return WS_NO_ERR;
}

long WSDxscrFrameDev::createPixmap(){
  if (getGC() == 0){
    return WS_ERR;
  }

  WSCushort w,h;    
  w = _work_width;
  if (_work_width <1){
    w = 1;
  }
  h = _work_height;
  if (_work_height <1){
    h = 1;
  }
  Pixmap pix = WSGFxGetPixmap(w,h);
  setPixmap(pix);
  _setup_pixmap(0,0,w,h,_bg_no,_bp_no);
  exposeExecute(0,0,w,h);
  return WS_NO_ERR;

}
long WSDxscrFrameDev::createWindow(){
  if (_scr_form != 0){
    WSDxformDev* xdev = getParentAreaDev();
    if (xdev != NULL && xdev->getWidget() != _pwidget){
      if (_widget != NULL){
        XtRemoveCallback(_widget,XtNdestroyCallback,_evh_delete2,this);
      }
    }else{
      return WS_NO_ERR;
    }
  }
  short x,y;    
  WSCushort w,h;    
  getWindowSize(&x,&y,&w,&h);
  if (w == 0){
    w = 1;
  }
  if (h == 0){
    h = 1;
  }
  _h_scr_pos = 0;
  _v_scr_pos = 0;

  WSDdev*      pdev = getParentDev();
  if (pdev == NULL){
    assert(0);
    return WS_ERR;
  }
  WSDxformDev* xdev = (WSDxformDev*)pdev->cast("WSDxformDev");
  if (xdev == NULL){
    return WS_ERR;
  }

  Arg args[12];
  long anum =0;
  if (_bg != -1){
    WSDcolor* color = WSGIappColorSet()->getColor(_bg);
    if (color != NULL){
       XtSetArg(args[anum],XtNbackground,color->getValue1()); anum++;
    }
  }

  XtSetArg(args[anum],XtNbackgroundPixmap,UNSPECIFIED_PIXMAP); anum++;
  XtSetArg(args[anum],XtNx,x); anum++;
  XtSetArg(args[anum],XtNy,y); anum++;
  XtSetArg(args[anum],XtNwidth,w); anum++;
  XtSetArg(args[anum],XtNheight,h); anum++;
  XtSetArg(args[anum],XtNborderWidth,0); anum++;

  _pwidget = xdev->getWidget();
  _scr_form = XtCreateWidget("xscrarea",formWidgetClass,_pwidget,args,6);

  anum =0;
  if (_bg != -1){
    WSDcolor* color = WSGIappColorSet()->getColor(_bg);
    if (color != NULL){
       XtSetArg(args[anum],XtNbackground,color->getValue1()); anum++;
    }
  }
  XtSetArg(args[anum],XtNbackgroundPixmap,UNSPECIFIED_PIXMAP); anum++;
  XtSetArg(args[anum],XtNx,0); anum++;
  XtSetArg(args[anum],XtNy,0); anum++;
  XtSetArg(args[anum],XtNwidth,1000); anum++;
  XtSetArg(args[anum],XtNheight,1000); anum++;
  XtSetArg(args[anum],XtNborderWidth,0);anum++;

  _widget = XtCreateWidget("wsdxwa",formWidgetClass, _scr_form,args,anum);
  XtManageChild(_widget);

  XtAddEventHandler(_widget,ExposureMask,False,(XtEventHandler)_evh_expose,(WSDxformDev*)this);
  XtAddEventHandler(_widget,ButtonPressMask,False,(XtEventHandler)_evh_btn_press,(WSDxformDev*)this);
  XtAddEventHandler(_widget,ButtonReleaseMask,False,(XtEventHandler)_evh_btn_release,(WSDxformDev*)this);
  XtAddEventHandler(_widget,ButtonMotionMask | PointerMotionMask,False,(XtEventHandler)_evh_mouse_move,(WSDxformDev*)this);
  XtAddEventHandler(_scr_form,StructureNotifyMask,False,(XtEventHandler)_evh_resize,this);
  XtAddEventHandler(_widget,EnterWindowMask,False,(XtEventHandler)_evh_mouse_in,(WSDxformDev*)this);
  XtAddEventHandler(_widget,LeaveWindowMask,False,(XtEventHandler)_evh_mouse_out,(WSDxformDev*)this);
  XtAddEventHandler(_widget,KeyPressMask | KeyReleaseMask,False,(XtEventHandler)_evh_dummy,(WSDxformDev*)this);
  XtAddCallback(_widget,XtNdestroyCallback,_evh_delete2,this);
//printf("WSDxscrFrameDev::createWindow this=0x%x _widget=0x%x _scr_form=0x%x\n",this,_widget,_scr_form);
  return WS_NO_ERR;
}

long WSDxscrFrameDev::destroyWindow(){
//printf("WSDxscrFrameDev::destroyWindow this=0x%x _widget=0x%x _scr_form=0x%x\n",this,_widget,_scr_form);
  if (_widget != 0){
    XtRemoveEventHandler(_widget,ExposureMask,False,(XtEventHandler)_evh_expose,(WSDxformDev*)this);
    XtRemoveEventHandler(_widget,ButtonPressMask,False,(XtEventHandler)_evh_btn_press,(WSDxformDev*)this);
    XtRemoveEventHandler(_widget,ButtonReleaseMask,False,(XtEventHandler)_evh_btn_release,(WSDxformDev*)this);
    XtRemoveEventHandler(_widget,ButtonMotionMask | PointerMotionMask,False,(XtEventHandler)_evh_mouse_move,(WSDxformDev*)this);
    XtRemoveEventHandler(_widget,EnterWindowMask,False,(XtEventHandler)_evh_mouse_in,(WSDxformDev*)this);
    XtRemoveEventHandler(_widget,LeaveWindowMask,False,(XtEventHandler)_evh_mouse_out,(WSDxformDev*)this);
    XtRemoveEventHandler(_widget,KeyPressMask | KeyReleaseMask,False,(XtEventHandler)_evh_dummy,(WSDxformDev*)this);
    XtRemoveCallback(_widget,XtNdestroyCallback,_evh_delete2,this);
    XtDestroyWidget(_widget);
  }
  if (_scr_form != 0){
    XtRemoveEventHandler(_scr_form,StructureNotifyMask,False,(XtEventHandler)_evh_resize,this);
    XtDestroyWidget(_scr_form);
  }
  _clear_widget();
  return WS_NO_ERR;
}

long WSDxscrFrameDev::setVisible(WSCbool fl){

  WSCbool bk = getVisible();
  WSDdev::setVisible(fl);
  if (fl == False){
    WSDxformDev* xdev = getParentAreaDev();
    if (xdev != NULL && xdev->getWidget() == 0){
      destroyWindow();
    }else{
      if (_scr_form != 0){
        XtUnmanageChild(_scr_form);
      }
    }
  }else{

    if (_scr_form == 0){
      if ( createWindow() == WS_ERR){
	      return WS_ERR;
       }
    }

    if (getPixmapStyle() != WS_DIRECT_WINDOW){
      if (bk == False){
        //delete the pixmap to create int the expose handler
        destroyPixmap(); 
      }
    }
    Arg args[12];
    long anum =0;
    XtSetArg(args[anum],XtNborderWidth,0);anum++;
    XtSetValues((Widget)_scr_form,args,anum);
    XtSetValues((Widget)_widget,args,anum);
    XtManageChild(_scr_form);
  }
  return WS_NO_ERR;
}
void WSDxscrFrameDev::_clear_widget(){
  _pwidget = 0;
  _scr_form = 0;
  _widget = 0;
  setInitialized(False);
}
void WSDxscrFrameDev::_evh_delete2(Widget w,XtPointer ptr,XtPointer ){
   WSDxscrFrameDev* dev = (WSDxscrFrameDev*)ptr;
//printf("WSDxscrFrameDev::_evh_delete2 this=0x%x w=0x%x _widget=0x%x\n",dev,w,dev->_widget);
   if (dev->_widget != w){
     return;
   }
   dev->_clear_widget();
}
void WSDxscrFrameDev::_evh_resize(Widget,XtPointer ptr,XEvent* ev,WSCbool*){
  WSGIxwinAppDev()->setXEvent(ev);
  WSDxscrFrameDev* dev = (WSDxscrFrameDev*)ptr;
  if (ev->type == ConfigureNotify){
    Position x;
    Position y;
    Dimension width;
    Dimension height;
    Arg args[4];
    XtSetArg(args[0],XtNx,&x);
    XtSetArg(args[1],XtNy,&y);
    XtSetArg(args[2],XtNwidth,&width);
    XtSetArg(args[3],XtNheight,&height);
    XtGetValues(dev->_scr_form,args,4);

    WSCrect area;
    area.setRect(x,y,width,height);
    dev->onResize(&area);
    WSGIxwinAppDev()->setXEvent(NULL);
  }
}
void WSDxscrFrameDev::getDispAddr(short* ox,short* oy){

  short gx,gy;
  WSDwindowDev::getDispAddr(&gx,&gy);

  gx -=_h_scr_pos;
  gy -=_v_scr_pos;

  *ox = gx;
  *oy = gy;
}

