//
// 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/Xlib.h>
#include <WSDfont.h>
#include <WSCfontSet.h>
#include <WSDcolor.h>
#include <WSCcolorSet.h>
#include <WSDimage.h>
#include <WSCimageSet.h>
#include <WSCstring.h>
#include <WSCvarc.h>
#include <WSClocaleSet.h>
#include <x11/WSxcom.h>
#include <x11/WSDxappDev.h>
#include <x11/WSDxdraw.h>
#include <x11/WSDximage.h>

//#define TDBG

WSMFclassInit(WSDxdraw,WSCroot);

static long fgcolor = -100;
static long bgcolor = -100;
static WSCulong _fg_color_no = 0xffffffff;
static WSCulong _bg_color_no = 0xffffffff;
static signed char _fill_type = -1;

static char _line_dash_type1[] = {3, 3};
static char _line_dash_type2[] = {10, 10};
static char _line_dash_type3[] = {20, 20};
static char _line_dash_type4[] = {20, 5, 5, 5};
static char _line_dash_type5[] = {20, 5, 5, 5, 5, 5};
static char _line_dash_type6[] = {40, 5, 5, 5};
static char _line_dash_type7[] = {40, 5, 5, 5, 5, 5};
static char _line_dash_type8[] = {1, 2};

static int _line_dash_type_seg1 = 2;
static int _line_dash_type_seg2 = 2;
static int _line_dash_type_seg3 = 2;
static int _line_dash_type_seg4 = 4;
static int _line_dash_type_seg5 = 6;
static int _line_dash_type_seg6 = 4;
static int _line_dash_type_seg7 = 6;
static int _line_dash_type_seg8 = 2;

static WSCuchar _hatch_pattern1[] = {0xc0, 0xc0, 0x30, 0x30, 0x0c, 0x0c, 0x03, 0x03};
static WSCuchar _hatch_pattern2[] = {0x03, 0x03, 0x0c, 0x0c, 0x30, 0x30, 0xc0, 0xc0};
static WSCuchar _hatch_pattern3[] = {0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc, 0xcc};
static WSCuchar _hatch_pattern4[] = {0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00};
static WSCuchar _hatch_pattern5[] = {0xcc, 0xcc, 0x33, 0x33, 0xcc, 0xcc, 0x33, 0x33};
static WSCuchar _hatch_pattern6[] = {0xff, 0xff, 0xcc, 0xcc, 0xff, 0xff, 0xcc, 0xcc};
static WSCuchar _hatch_pattern7[] = {0xcc, 0xcc, 0x00, 0x00, 0xcc, 0xcc, 0x00, 0x00};
static WSCuchar _hatch_pattern8[] = {0xcc, 0xaa, 0xcc, 0xaa, 0xcc, 0xaa, 0xcc, 0xaa};
static Pixmap _hatch[9] = { 0,0,0,0,0,0,0,0,0 };

static short _clip_x = -1;
static short _clip_y = -1;
static short _clip_w = -1;
static short _clip_h = -1;

WSDxdraw::WSDxdraw(){
  _fg_color = 0;
  _bg_color = 0;
  _line_width = -1;
  _line_type = -1;
  _clipping = False;
}
WSDxdraw::~WSDxdraw(){}

long WSDxdraw::setForeColor(short cno){
  if (_gc == 0 || _window == 0){
    return fgcolor;
  }
  if (cno == fgcolor){
    if (_fg_color_no == 0xffffffff){
      WSDcolor*  color = WSGIappColorSet()->getColor(cno);
      if (color != NULL){
        _fg_color_no = (WSCulong )color->getValue1();
      }else{
        return fgcolor;
      }
    }
    if (_fg_color != _fg_color_no){
       XSetForeground(_display,_gc,_fg_color_no);
    }else if (_fg_color_no == 0){ //fail safe for existing the case _fg_color == _fg_color_no == 0
       XSetForeground(_display,_gc,_fg_color_no);
    }
    _fg_color = _fg_color_no;
    fgcolor = cno;
    return fgcolor;
  }

  long bk = fgcolor;
  WSDcolor*  color = WSGIappColorSet()->getColor(cno);
  if (color != NULL){
    _fg_color_no = (WSCulong )color->getValue1();
    if (_fg_color != _fg_color_no){
      XSetForeground(_display,_gc,_fg_color_no);
    }else if (_fg_color_no == 0){ //fail safe for existing the case _fg_color == _fg_color_no == 0
      XSetForeground(_display,_gc,_fg_color_no);
    }
    _fg_color = _fg_color_no;
    fgcolor = cno;
  }

  return bk;
}

long WSDxdraw::setBackColor(short cno){
  if (_gc == 0 || _window == 0){
    return bgcolor;
  }

  if (cno == bgcolor){
    if (_bg_color_no == 0xffffffff){
      WSDcolor*  color = WSGIappColorSet()->getColor(cno);
      if (color != NULL){
        _bg_color_no = (WSCulong )color->getValue1();
      }else{
        return bgcolor;
      }
    }
    if (_bg_color != _bg_color_no){
       XSetBackground(_display,_gc,_bg_color_no);
    }else if (_bg_color_no == 0){
       XSetBackground(_display,_gc,_bg_color_no);
    }
    _bg_color = _bg_color_no;
    bgcolor = cno;
    return bgcolor;
  }
  short bk = bgcolor;
  WSDcolor*  color = WSGIappColorSet()->getColor(cno);
  if (color != NULL){
    _bg_color_no = (WSCulong )color->getValue1();
    if (_bg_color != _bg_color_no){
      XSetBackground(_display,_gc,_bg_color_no);
    }else if (_bg_color_no == 0){
      XSetBackground(_display,_gc,_bg_color_no);
    }
    _bg_color = _bg_color_no;
    bgcolor = cno;
  }
  return bk;
}
long WSDxdraw::setForeColor(WSDcolor* color){
  if (_gc == 0 || _window == 0){
    return fgcolor;
  }
  if (color == NULL){
    return fgcolor;
  }
  short cno = color->getId();
  if (cno == fgcolor){
    if (_fg_color_no == 0xffffffff){
      if (color != NULL){
        _fg_color_no = (WSCulong )color->getValue1();
      }else{
        return fgcolor;
      }
    }
    if (_fg_color != _fg_color_no){
       XSetForeground(_display,_gc,_fg_color_no);
    }else if (_fg_color_no == 0){ //fail safe for existing the case _fg_color == _fg_color_no == 0
       XSetForeground(_display,_gc,_fg_color_no);
    }
    _fg_color = _fg_color_no;
    fgcolor = cno;
    return fgcolor;
  }

  long bk = fgcolor;
  if (color != NULL){
    _fg_color_no = (WSCulong )color->getValue1();
    if (_fg_color != _fg_color_no){
      XSetForeground(_display,_gc,_fg_color_no);
    }else if (_fg_color_no == 0){ //fail safe for existing the case _fg_color == _fg_color_no == 0
      XSetForeground(_display,_gc,_fg_color_no);
    }
    _fg_color = _fg_color_no;
    fgcolor = cno;
  }

  return bk;
}

long WSDxdraw::setBackColor(WSDcolor* color){
  if (_gc == 0 || _window == 0){
    return bgcolor;
  }
  if (color == NULL){
    return bgcolor;
  }
  short cno = color->getId();
  if (cno == bgcolor){
    if (_bg_color_no == 0xffffffff){
      if (color != NULL){
        _bg_color_no = (WSCulong )color->getValue1();
      }else{
        return bgcolor;
      }
    }
    if (_bg_color != _bg_color_no){
       XSetBackground(_display,_gc,_bg_color_no);
    }else if (_bg_color_no == 0){
       XSetBackground(_display,_gc,_bg_color_no);
    }
    _bg_color = _bg_color_no;
    bgcolor = cno;
    return bgcolor;
  }
  short bk = bgcolor;
  if (color != NULL){
    _bg_color_no = (WSCulong )color->getValue1();
    if (_bg_color != _bg_color_no){
      XSetBackground(_display,_gc,_bg_color_no);
    }else if (_bg_color_no == 0){
      XSetBackground(_display,_gc,_bg_color_no);
    }
    _bg_color = _bg_color_no;
    bgcolor = cno;
  }
  return bk;
}
long WSDxdraw::setLineWidth(short width){
  if (_gc == 0 || _window == 0){
    return -1;
  }

  if (_line_width == width){
    return _line_width;
  }
  long bk = _line_width;
  _line_width = width;

  long linet = _line_type;
  _line_type = -1; 
  setLineDashType(linet);

  return bk;
}

//#define CAPSTYLE  CapButt
#define CAPSTYLE  CapNotLast

long WSDxdraw::setLineDashType(char type){
  if (_line_type == type){
    return type;
  }
  if (_gc == 0 || _window == 0){
    return -1;
  }
  long bk = _line_type;
  _line_type = type;
  switch(type){
    case 0:
//      XSetLineAttributes(_display,_gc,_line_width, LineSolid,CapButt,WS_JOIN);
      XSetLineAttributes(_display,_gc,_line_width, LineSolid,CAPSTYLE,WS_JOIN);
      break;

    case 1:
      XSetDashes(_display,_gc,0,_line_dash_type1,_line_dash_type_seg1);
//      XSetLineAttributes(_display,_gc,_line_width, LineOnOffDash,CapButt,WS_JOIN);
      XSetLineAttributes(_display,_gc,_line_width, LineOnOffDash,CAPSTYLE,WS_JOIN);
      break;
    case 2:
      XSetDashes(_display,_gc,0,_line_dash_type2,_line_dash_type_seg2);
      XSetLineAttributes(_display,_gc,_line_width, LineOnOffDash,CAPSTYLE,WS_JOIN);
      break;
    case 3:
      XSetDashes(_display,_gc,0,_line_dash_type3,_line_dash_type_seg3);
      XSetLineAttributes(_display,_gc,_line_width, LineOnOffDash,CAPSTYLE,WS_JOIN);
      break;
    case 4:
      XSetDashes(_display,_gc,0,_line_dash_type4,_line_dash_type_seg4);
      XSetLineAttributes(_display,_gc,_line_width, LineOnOffDash,CAPSTYLE,WS_JOIN);
      break;
    case 5:
      XSetDashes(_display,_gc,0,_line_dash_type5,_line_dash_type_seg5);
      XSetLineAttributes(_display,_gc,_line_width, LineOnOffDash,CAPSTYLE,WS_JOIN);
      break;
    case 6:
      XSetDashes(_display,_gc,0,_line_dash_type6,_line_dash_type_seg6);
      XSetLineAttributes(_display,_gc,_line_width, LineOnOffDash,CAPSTYLE,WS_JOIN);
      break;
    case 7:
      XSetDashes(_display,_gc,0,_line_dash_type7,_line_dash_type_seg7);
      XSetLineAttributes(_display,_gc,_line_width, LineOnOffDash,CAPSTYLE,WS_JOIN);
       break;
    case 8:
      XSetDashes(_display,_gc,0,_line_dash_type8,_line_dash_type_seg8);
      XSetLineAttributes(_display,_gc,_line_width, LineOnOffDash,CAPSTYLE,WS_JOIN);
       break;
    default:
      XSetLineAttributes(_display,_gc,_line_width, LineSolid,CAPSTYLE,WS_JOIN);
  }
  return bk;
}
long WSDxdraw::setHatchPattern(char type){
  if (_gc == 0 || _window == 0){
    return -1;
  }
  if (_fill_type == type){
    return type;
  }
  long bk = _fill_type;
  if (type == 0 ){
    XSetFillStyle(_display,_gc,FillSolid);
    _fill_type = 0;
    return bk;
  }
  _fill_type = type;
  Pixmap _htch = 0;
  WSDxappDev* app   = WSGIxwinAppDev(); 
  switch(type){
    case 1: if (_hatch[type] == 0){
              _hatch[type] = XCreateBitmapFromData(_display,
                       XtWindow((Widget)app->appWidget()),
                       (char*)_hatch_pattern1,8,8);
            };
            _htch = _hatch[type];
            break;
    case 2: if (_hatch[type] == 0){
              _hatch[type] = XCreateBitmapFromData(_display,
                       XtWindow((Widget)app->appWidget()),
                       (char*)_hatch_pattern2,8,8);
            };
            _htch = _hatch[type];
            break;
    case 3: if (_hatch[type] == 0){
              _hatch[type] = XCreateBitmapFromData(_display,
                       XtWindow((Widget)app->appWidget()),
                       (char*)_hatch_pattern3,8,8);
            };
            _htch = _hatch[type];
            break;
    case 4: if (_hatch[type] == 0){
              _hatch[type] = XCreateBitmapFromData(_display,
                       XtWindow((Widget)app->appWidget()),
                       (char*)_hatch_pattern4,8,8);
            };
            _htch = _hatch[type];
            break;
    case 5: if (_hatch[type] == 0){
              _hatch[type] = XCreateBitmapFromData(_display,
                       XtWindow((Widget)app->appWidget()),
                       (char*)_hatch_pattern5,8,8);
            };
            _htch = _hatch[type];
            break;
    case 6: if (_hatch[type] == 0){
              _hatch[type] = XCreateBitmapFromData(_display,
                       XtWindow((Widget)app->appWidget()),
                       (char*)_hatch_pattern6,8,8);
            };
            _htch = _hatch[type];
            break;
    case 7: if (_hatch[type] == 0){
              _hatch[type] = XCreateBitmapFromData(_display,
                       XtWindow((Widget)app->appWidget()),
                       (char*)_hatch_pattern7,8,8);
            };
            _htch = _hatch[type];
            break;
    case 8: if (_hatch[type] == 0){
              _hatch[type] = XCreateBitmapFromData(_display,
                       XtWindow((Widget)app->appWidget()),
                       (char*)_hatch_pattern8,8,8);
            };
            _htch = _hatch[type];
            break;
  }
  if (_htch != 0){
    XSetFillStyle(_display,_gc,FillStippled);
    XSetStipple(_display,_gc,_htch);
  }else{
    XSetFillStyle(_display,_gc,FillSolid);
  }
  return bk;
}
long WSDxdraw::beginDraw(WSDdev* dev,long val1,long val2,long val3){
  _dev = dev;
  _display = (Display*)val1;
  _window = (Window)val2;

  if (_gc != (GC)val3){
    _fg_color = 0;
    _bg_color = 0;
//    _line_width = -1;
//    _line_type = -1;
    _gc =     (GC)val3;
    _fill_type = -1;
  }
//  if (_line_type != 0 || _line_width != 1){
    XSetLineAttributes(_display,_gc,0,
                          LineSolid,CapButt,WS_JOIN);
    _line_width = 1;
    _line_type = 0;
//  }
  if (_fill_type != 0){
    XSetFillStyle(_display,_gc,FillSolid);
    _fill_type = 0;
  }
  if (fgcolor == -1){
    fgcolor = WSGFcolor("#000000");
    WSDcolor*  color = WSGIappColorSet()->getColor(fgcolor);
    if (color != NULL){
      _fg_color_no = (WSCulong )color->getValue1();
      XSetForeground(_display,_gc,_fg_color_no);
      _fg_color = _fg_color_no;
    }else{
      return WS_NO_ERR;
    }
  }else{
    if (_fg_color != _fg_color_no){
      XSetForeground(_display,_gc,_fg_color_no);
      _fg_color = _fg_color_no;
    }
  }
  if (bgcolor == -1){
    bgcolor = WSGFcolor("#ffffff");
    WSDcolor*  color = WSGIappColorSet()->getColor(bgcolor);
    if (color != NULL){
      _bg_color_no = (WSCulong )color->getValue1();
      XSetBackground(_display,_gc,_bg_color_no);
      _bg_color = _bg_color_no;
    }else{
      return WS_NO_ERR;
    }
  }else{
    if (_bg_color != _bg_color_no){
      XSetBackground(_display,_gc,_bg_color_no);
      _bg_color = _bg_color_no;
    }
  }
  return WS_NO_ERR;
}

long WSDxdraw::endDraw(){
  if (_gc == 0 || _window == 0){
    return WS_ERR;
  }
  if (_clipping == True){
    XSetClipMask(_display, _gc ,None);
    _clipping = False;
    _clip_x = -1;
    _clip_y = -1;
    _clip_w = -1;
    _clip_h = -1;
  }
  return WS_NO_ERR;
}

long WSDxdraw::setRegion(short x,short y,WSCushort w,WSCushort h){
  if (_gc == 0 || _window == 0){
    return WS_ERR;
  }
  if (_clip_x != x || _clip_y != y || _clip_w != w || _clip_h != h){
//printf("WSDxdraw::setRegion win=0x%x gc=0x%x %d %d %d %d\n",_window,_gc,x,y,w,h);
    _clip_x = x;
    _clip_y = y;
    _clip_w = w;
    _clip_h = h;
    XRectangle xrect[1];
    xrect[0].x = (WSCuint)x;
    xrect[0].y = (WSCuint)y;
    xrect[0].width = (WSCuint)w;
    xrect[0].height = (WSCuint)h;

    _clipping = True;
    XSetClipRectangles(_display,_gc,0,0,xrect,1,Unsorted);
  }
  return WS_NO_ERR;
}

long WSDxdraw::drawArc(short x,short y,WSCushort w,WSCushort h,short a1,short a2){
  if (_gc == 0 || _window == 0){
    return WS_ERR;
  }
  XDrawArc(_display,_window,_gc,x,y,w,h,a1,a2);
  return WS_NO_ERR;
}
long WSDxdraw::drawFillArc(short x,short y,WSCushort w,WSCushort h,short a1,short a2,char kind){
  if (_gc == 0 || _window == 0){
    return WS_ERR;
  }
  if (kind == WS_PI){
    XSetArcMode(_display,_gc,ArcPieSlice);
  }else{
    XSetArcMode(_display,_gc,ArcChord);
  }
  XFillArc(_display,_window,_gc,x,y,w,h,a1,a2);
  return WS_NO_ERR;
}
long WSDxdraw::drawLine(short x1,short y1,short x2,short y2){
  if (_gc == 0 || _window == 0){
    return WS_ERR;
  }
  XDrawLine(_display,_window,_gc,(int)x1,(int)y1,(int)x2,(int)y2); 
  return WS_NO_ERR;
}
long WSDxdraw::drawLines(WSCpoint* points,long num){
  if (_gc == 0 || _window == 0){
    return WS_ERR;
  }
  if (_line_width < 4){
    long i; 
    for(i=0; i<num -1;i++){
      XDrawLine(_display,_window,_gc,(int)points[i].x,(int)points[i].y, 
                (int)points[i+1].x,(int)points[i+1].y);
    }
  }else{
    XPoint* pts = new XPoint[num];
    long i;
    for(i=0; i<num; i++){
      pts[i].x = points[i].x;
      pts[i].y = points[i].y;
    }
    XDrawLines(_display,_window,_gc,pts,num,CoordModeOrigin); 
    delete pts;
  }
  return WS_NO_ERR;
}
long WSDxdraw::drawRect(short x,short y,WSCushort w,WSCushort h){
  if (_gc == 0 || _window == 0){
    return WS_ERR;
  }
  XDrawRectangle(_display,_window,_gc,(int)x,(int)y,(WSCuint)w-1,(WSCuint)h-1); 
  return WS_NO_ERR;
}
long WSDxdraw::drawFillRect(short x,short y,WSCushort w,WSCushort h){
  if (_gc == 0 || _window == 0){
    return WS_ERR;
  }
//printf("WSDxdraw::drawFillRect win=0x%x gc=0x%x %d %d %d %d\n",_window,_gc,x,y,w,h);
  XFillRectangle(_display,_window,_gc,(int)x,(int)y,(WSCuint)w,(WSCuint)h); 
  return WS_NO_ERR;
}
long WSDxdraw::drawRects(WSCrect* rects,long num){
  if (_gc == 0 || _window == 0){
    return WS_ERR;
  }
  long i;
  for(i=0; i<num; i++){
    XDrawRectangle(_display,_window,_gc,rects[i].x,rects[i].y,
                    rects[i].width,rects[i].height); 
  }
  return WS_NO_ERR;
}
long WSDxdraw::drawFillRects(WSCrect* rects,long num){
  if (_gc == 0 || _window == 0){
    return WS_ERR;
  }
  long i;
  for(i=0; i<num; i++){
    XFillRectangle(_display,_window,_gc,rects[i].x,rects[i].y,
                    rects[i].width,rects[i].height); 
  }
  return WS_NO_ERR;
}
long WSDxdraw::drawPoly(WSCpoint* points,long num){
  if (_gc == 0 || _window == 0){
    return WS_ERR;
  }
  XPoint* pts = new XPoint[num+1];
//  memcpy(pts,points,sizeof(XPoint)*num);
  long i;
  for(i=0; i<num; i++){
    pts[i].x = points[i].x;
    pts[i].y = points[i].y;
  }
  pts[num].x = points[0].x;
  pts[num].y = points[0].y;
  XDrawLines(_display,_window,_gc,pts,num+1,CoordModeOrigin); 
  delete pts;
  return WS_NO_ERR;
}

long WSDxdraw::drawFillPoly(WSCpoint* points,long num){
  if (_gc == 0 || _window == 0){
    return WS_ERR;
  }
  XPoint* pts = new XPoint[num];
  long i;
  for(i=0; i<num; i++){
    pts[i].x = points[i].x;
    pts[i].y = points[i].y;
  }
  XFillPolygon(_display,_window,_gc,pts,num,Nonconvex,CoordModeOrigin);
  delete pts;
  return WS_NO_ERR;
}

long WSDxdraw::drawImage(short x,short y,WSCushort w,WSCushort h,WSDimage* image,char align){

  if (_gc == 0 || _window == 0){
    return WS_ERR;
  }
  Pixmap pix1 = (Pixmap)image->getValue1();
  Pixmap pix2 = (Pixmap)image->getValue2();

  WSCushort pw = image->getImageWidth();
  WSCushort ph = image->getImageHeight();
  short xoff = 0;
  short yoff = 0;
  if (align == WS_CENTER){
    xoff = ((short)w - (short)pw)/2;
    yoff = ((short)h - (short)ph)/2;
  }else
  if (align == WS_LEFT){
    yoff = ((short)h - (short)ph)/2;
  }else
  if (align == WS_LEFT_TOP){
    xoff = 0;
    yoff = 0;
  }else
  if (align == WS_TOP){
    xoff = ((short)w - (short)pw)/2;
    yoff = 0;
  }else
  if (align == WS_RIGHT){
    xoff = ((short)w - (short)pw);
    yoff = ((short)h - (short)ph)/2;
  }else
  if (align == WS_BOTTOM){
    xoff = ((short)w - (short)pw)/2;
    yoff = ((short)h - (short)ph);
  }else
  if (align == WS_LEFT_BOTTOM){
    xoff = 0;
    yoff = ((short)h - (short)ph);
  }else
  if (align == WS_RIGHT_TOP){
    xoff = ((short)w - (short)pw);
    yoff = 0;
  }else
  if (align == WS_RIGHT_BOTTOM){
    xoff = ((short)w - (short)pw);
    yoff = ((short)h - (short)ph);
  }
  if ((long)pix1 == -1 || pix1 == 0){
    return WS_NO_ERR;
  }
  if ((long)pix2 != -1 && pix2 != 0){
    XSetClipMask(_display,_gc,pix2);
    XSetClipOrigin(_display,_gc,x+xoff,y+yoff);
  }
  long dx1,dy1;
  long dw1,dh1;
  long dx,dy;
  long dw,dh;
  WSGFandArea(x,y,w,h,_clip_x,_clip_y,_clip_w,_clip_h,&dx1,&dy1,(WSCulong*)&dw1,(WSCulong*)&dh1);
  WSGFandArea(dx1,dy1,dw1,dh1,x+xoff,y+yoff,pw,ph,&dx,&dy,(WSCulong*)&dw,(WSCulong*)&dh);

  XCopyArea(_display,pix1,_window,_gc, dx -x -xoff,dy -y -yoff, dw,dh,dx,dy);
  if ((long)pix2 != -1 && pix2 != 0){
    short clx = _clip_x;
    _clip_x = -1;
    setRegion(clx,_clip_y,_clip_w,_clip_h);
  }
  return WS_NO_ERR;
}
long WSDxdraw::drawStretchedImage(short x,short y,WSCushort w,WSCushort h,WSDimage* image){
  if (_gc == 0 || _window == 0){
    return WS_ERR;
  }
  Pixmap pix1 = (Pixmap)image->getValue1();
//  Pixmap pix2 = (Pixmap)image->getValue2();

//  WSCushort pw = image->getImageWidth();
//  WSCushort ph = image->getImageHeight();

  if ((long)pix1 == -1 || (long)pix1 == 0){
    return WS_NO_ERR;
  }
  long dx,dy;
  WSCulong dw,dh;
  WSGFandArea(x,y,w,h,_clip_x,_clip_y,_clip_w,_clip_h,&dx,&dy,&dw,&dh);
  if (dw == 0 || dh == 0){
    return WS_NO_ERR;
  }

  if ((long)pix1 != -1 && (long)pix1 != 0){
    XSetClipMask(_display,_gc,0);
  }

  XImage* img = (XImage*)image->getValue3();
  if ((long)img == 0 ||
      (long)img == -1 ){
    WSDximage* ximage = (WSDximage*)image->cast("WSDximage");
    if (ximage == NULL){
      return WS_ERR;
    }
    ximage->createImage();
    img = (XImage*)image->getValue3();
    if (img == NULL ||(long)img == -1){
      return WS_ERR;
    }
  }
  XImage* img_mask = NULL;
  if (image->cast("WSDximage")){
    WSDximage* ximage = (WSDximage*)image->cast("WSDximage");
     img_mask = ximage->createMaskImage();
//printf("img_mask->bytes_per_line=%d\n",img_mask->bytes_per_line);
//printf("img_mask->depth=%d\n",img_mask->depth);
  }
  long display_depth = XDefaultDepth(_display,
                                     XDefaultScreen(_display));
//printf("display_depth=%d\n",display_depth);
  WSDxappDev* app   = WSGIxwinAppDev(); 
  long bit_pad = 32;
  if (display_depth == 32){
     bit_pad = 32;
  }else
  if (display_depth == 24){
     bit_pad = 32; 
  }else
  if (display_depth == 16){
     bit_pad = 16;
  }else{ 
     bit_pad = 8;
  }
  Visual* visual = XDefaultVisual(_display,XDefaultScreen(_display));
//  XVisualInfo vinf;

  XImage* img2 = XCreateImage(_display, visual,
                       display_depth,
                       ZPixmap,0,0,
                       dw, dh, bit_pad,0);
  XInitImage(img2);
  int msb_flag = (ImageByteOrder(_display) == MSBFirst)?1:0;
  WSCulong iw = image->getImageWidth();
  WSCulong ih = image->getImageHeight();
  img2->data = new char[img2->bytes_per_line * dh ];
//printf("img2->bytes_per_line=%d\n",img2->bytes_per_line);
  long bit = img2->bits_per_pixel;

  XImage* img_mask2 = NULL;
  WSCulong iwm = 0;
  WSCulong iwm2 = 0;
//  WSCulong ihm = image->getImageHeight();
  if (img_mask != NULL){
    img_mask2 = XCreateImage(_display, visual,
                       1,
                       ZPixmap,0,0,
                       dw, dh,8,0);
    XInitImage(img_mask2);
    img_mask2->data = new char[img_mask2->bytes_per_line * dh ];
    iwm = img_mask->bytes_per_line;
    iwm2 = img_mask2->bytes_per_line;
//printf("img_mask2->bytes_per_line=%d\n",img_mask2->bytes_per_line);
  }

  long i=0;
  long j=0;
  long ptr = 0;
  long pt = 0;
  for(i=dy-y; i<dy-y +(long)dh; i++){
    for(j=dx-x; j<dx -x +(long)dw; j++){
//      long pt = (long)((double)j*iw/w + 0.5 + (int)((double)i*ih/h+0.5)*iw);
//      long pt = (long)((double)j*iw/w) + (long)((double)i*ih/h)*(iw + iw%2);
      if (display_depth == 32){
        pt = (long)((double)j*iw/w) + (long)((double)i*ih/h)*iw;
        pt = pt *4;
        ptr = ((j -dx +x)+(i -dy +y)*dw)*4;
        img2->data[ptr++] = img->data[pt];
        img2->data[ptr++] = img->data[pt+1];
        img2->data[ptr++] = img->data[pt+2];
        img2->data[ptr++] = img->data[pt+3];
      }else
      if (display_depth == 24){
        if (bit == 32){
          pt = (long)((double)j*iw/w) + (long)((double)i*ih/h)*iw;
          pt = pt *4;
          ptr = ((j -dx +x)+(i -dy +y)*dw)*4;
          img2->data[ptr++] = img->data[pt];
          img2->data[ptr++] = img->data[pt+1];
          img2->data[ptr++] = img->data[pt+2];
          img2->data[ptr++] = img->data[pt+3];
        }else if (bit == 24){
          pt = (long)((double)j*iw/w)*3 + (long)((double)i*ih/h)*img->bytes_per_line;
          ptr = (j -dx +x)*3+(i -dy +y)*img2->bytes_per_line;
          img2->data[ptr++] = img->data[pt];
          img2->data[ptr++] = img->data[pt+1];
          img2->data[ptr++] = img->data[pt+2];
        }
      }else
      if (display_depth == 16 || display_depth == 15){
        pt = (long)((double)j*iw/w) + (long)((double)i*ih/h)*(iw + iw%2);
        pt = pt *2;
        ptr = ((j -dx +x)+(i -dy +y)*dw)*2;
        img2->data[ptr++] = img->data[pt];
        img2->data[ptr++] = img->data[pt+1];
      }else
      if (display_depth == 12){
        if (bit == 24){
          pt = (long)((double)j*iw/w) + (long)((double)i*ih/h)*iw;
          pt = pt *3;
          ptr = ((j -dx +x)+(i -dy +y)*dw)*3;
          img2->data[ptr++] = img->data[pt];
          img2->data[ptr++] = img->data[pt+1];
          img2->data[ptr++] = img->data[pt+2];
        }
      }else
      if (display_depth == 8){
        pt = (long)((double)j*iw/w) + (long)((double)i*ih/h)*img->bytes_per_line;
        ptr = ((j -dx +x)+(i -dy +y)*img2->bytes_per_line);
        img2->data[ptr++] = img->data[pt];
      }else
      if (display_depth == 4){
        pt = (long)((double)j*iw/w) + (long)((double)i*ih/h)*img->bytes_per_line;
        ptr = ((j -dx +x)+(i -dy +y)*img2->bytes_per_line);
        img2->data[ptr++] = img->data[pt];
      }else{
        pt = (long)((double)j*iw/w) + (long)((double)i*ih/h)*img->bytes_per_line;
        ptr = ((j -dx +x)+(i -dy +y)*img2->bytes_per_line);
        img2->data[ptr++] = img->data[pt];
      }
      if (img_mask2 != NULL){
        pt = (long)((double)j*iw/w)/8 + (long)((double)i*ih/h)*iwm;
        ptr = ((j -dx +x)/8+(i -dy +y)*img_mask2->bytes_per_line);
        WSCuchar val = img_mask2->data[ptr];
        long shiftd = (j -dx +x)%8;
        long shifts = ((int)((double)j*iw/w))%8;
        WSCuchar val2 = img_mask->data[pt];
        WSCuchar m = 1;
        if (!msb_flag){
          m <<= shifts;
        }else{
          m =0x80;
          m >>= shifts;
        }
        if (val2 & m){
          WSCuchar m = 1;
          m <<= shiftd;
//printf("ptr=%d %d,pt=%d %d %d 0x%x\n",ptr,shiftd,pt,shiftd,val2&m,m);
          val |= m;
        }else{
          WSCuchar m = 1;
          m <<= shiftd;
//printf("ptr=%d %d,pt=%d %d %d 0x%x\n",ptr,shiftd,pt,shiftd,val2&m,~m);
//TEST
          val &= ~m;
        }
        img_mask2->data[ptr] = val;
      }
    }
  }
  Pixmap newpix = WSGFxGetPixmap(dw,dh);
//  XPutImage(_display,newpix,_gc,img2,dx-x,dy-y,0,0,dw,dh);
  XPutImage(_display,newpix,_gc,img2,0,0,0,0,dw,dh);

  Pixmap pixm = 0;
  if (img_mask2 != NULL){
    pixm = XCreateBitmapFromData(XtDisplay(app->appWidget()),
                             XtWindow(app->appWidget()),img_mask2->data,dw,dh);

    if ((long)pixm != -1 && pixm != 0){
      XSetClipMask(_display,_gc,pixm);
      XSetClipOrigin(_display,_gc,dx,dy);
    }
  }


//  XCopyArea(_display,newpix,_window,_gc, dx -x,dy -y, dw,dh,dx,dy);
  XCopyArea(_display,newpix,_window,_gc, 0,0, dw,dh,dx,dy);

  WSGFxReleasePixmap(newpix);
  if ((long)pixm != -1 && pixm != 0){
//    XSetClipMask(_display,_gc,0);
    XDestroyImage(img_mask);
    XDestroyImage(img_mask2);
    XFreePixmap(XtDisplay(app->appWidget()),pixm);
  }
  if (img2->data != NULL){
    delete img2->data;
    img2->data = NULL;
  }
  XDestroyImage(img2);
//  if ((long)pix2 != -1 && pix2 != 0){
//    short clx = _clip_x;
//    _clip_x = -1;
//    setRegion(clx,_clip_y,_clip_w,_clip_h);
//  }
  if ((long)pix1 != -1 && (long)pix1 != 0){
    short clx = _clip_x;
    _clip_x = -1;
    setRegion(clx,_clip_y,_clip_w,_clip_h);
  }
  return WS_NO_ERR;
}


long WSDxdraw::drawImage(short x,short y,short sx,short sy,WSCushort w,WSCushort h,WSDimage* image){
  if (_gc == 0 || _window == 0){
    return WS_ERR;
  }
  Pixmap pix1 = (Pixmap)image->getValue1();
  Pixmap pix2 = (Pixmap)image->getValue2();

  if ((long)pix1 == -1 || pix1 == 0){
    return WS_NO_ERR;
  }
  if ((long)pix2 != -1 && pix2 != 0){
    XSetClipMask(_display,_gc,pix2);
    XSetClipOrigin(_display,_gc,sx,sy);
  }
  long dx,dy;
  long dw,dh;
  WSGFandArea(x,y,w,h,_clip_x,_clip_y,_clip_w,_clip_h,&dx,&dy,(WSCulong*)&dw,(WSCulong*)&dh);

  XCopyArea(_display,pix1,_window,_gc, dx -x +sx,dy -y +sy, dw,dh,dx,dy);
  if ((long)pix2 != -1 && pix2 != 0){
    short clx = _clip_x;
    _clip_x = -1;
    setRegion(clx,_clip_y,_clip_w,_clip_h);
  }
  return WS_NO_ERR;
}
long WSDxdraw::drawUString(long x,long y,WSCulong w,WSCulong h,
         WSCushort* str,char font,char align,long cur,WSCbool inter_cur,
         long scur1,long scur2){
  char* str1 = WSGFgetString(str,WS_EN_UTF8);
  WSCstring str2(str1,WS_EN_UTF8);
  long ret = drawString(x,y,w,h,&str2,font,align,cur,inter_cur,scur1,scur2);
  delete str1;
  return ret;
}
long WSDxdraw::drawFillUString(long x,long y,WSCulong w,WSCulong h,
           WSCushort* str,char font,char align,short cur,WSCbool inter_cur){
  char* str1 = WSGFgetString(str,WS_EN_UTF8);
  WSCstring str2(str1,WS_EN_UTF8);
  long ret = drawFillString(x,y,w,h,&str2,font,align,cur,inter_cur);
  delete str1;
  return ret;
}
long WSDxdraw::drawString(long x,long y,WSCulong w,WSCulong h,
         WSCstring* str,char font,char align,long cur,WSCbool inter_cur,
         long scur1,long scur2){
#ifdef TDBG
  printf("WSDxdraw::drawString start %d\n",WSGFclocktime());
#endif

  if (scur1 == scur2){
    scur1 = scur2 = 0;
  }
  if (scur1 > scur2){
    long bk = scur1;
    scur1 = scur2;
    scur2 = bk;
  }
  if (_gc == 0 || _window == 0){
    return WS_ERR;
  }
  short clx_bk = _clip_x;
  short cly_bk = _clip_y;
  WSCushort clw_bk = _clip_w;
  WSCushort clh_bk = _clip_h;
  long clx,cly;
  WSCulong clw,clh;
  WSGFandArea(x,y,w,h,_clip_x,_clip_y,_clip_w,_clip_h,&clx,&cly,&clw,&clh);
  setRegion(clx,cly,clw,clh);

  WSDfont* fn = WSGIappFontSet()->getFont(font);
  if (fn == NULL){
    fn = WSGIappFontSet()->getDefaultFont();
    if (fn == NULL){
      return WS_ERR;
    }
  }
  XFontStruct* efs = (XFontStruct*)fn->getValue1();
  XFontStruct* kfs = (XFontStruct*)fn->getValue2();
  XFontStruct* gfs = (XFontStruct*)fn->getValue3();
  long efontWidth = 14;
  long kfontWidth = 14;
  Font efid;
  if (efs == NULL || efs == (void*)-1){
    return WS_ERR;
  }else{
    efid = efs->fid;
    efontWidth = (long)efs->max_bounds.rbearing;
  }
  Font kfid;
  if (kfs == NULL || kfs == (void*)-1){
    kfid = efid;
    kfontWidth = efontWidth;
  }else{
    kfid = kfs->fid;
    kfontWidth = (long)kfs->max_bounds.rbearing;
  }
  Font gfid;
  if (gfs == NULL || gfs == (void*)-1){
    gfid = efid;
  }else{
    gfid = gfs->fid;
  }

  long fheight = (long)efs->max_bounds.ascent;
  long fheight2 = (long)kfs->max_bounds.ascent;

  if (str->isExist("\n") == -1){
    WSCrect   area;
    area.setRect(x,y,w,h);
    WSCpoint  point;
    WSGFcalcOneLineStringAddr(str,&area,align,fn,&point);
    char* tstr;
//    if (WSGIappLocaleSet()->getDefaultEncoding() == WS_EN_EUCJP){
//      tstr = str->getString(WS_EN_EUCJP);
//    }else{
      tstr = str->getString(WS_EN_UTF8);
//    }
    char* tstr2 = new char[strlen(tstr) + 8];
    strcpy(tstr2,tstr);
    strcat(tstr2," ");
    WSGFxdrawTextString( _display, _window, _gc, efs, kfs, gfs, _fg_color,
      _bg_color,point.x, point.y + fheight,
      tstr2, kfontWidth, efontWidth, fheight2,fheight,cur, inter_cur,_line_width,scur1,scur2);
    delete tstr2;
    setRegion(clx_bk,cly_bk,clw_bk,clh_bk);
    return WS_NO_ERR;
  }

  long num;
  WSCrect area;
  area.setRect(x,y,w,h);
  WSCpoint* points;

  WSGFcalcStringAddr(str,&area,align,fn,&points,&num);
  long i;
  str->seek(0);
  long lpos =0;
  long prelpos =0;
  for(i=0; i < num; i++){

    if (points[i].y + fheight < cly){
      lpos += prelpos;
      prelpos = str->_seek_next_line() +1;
//printf("lpos=%d prelpos=%d\n",lpos,prelpos);
      continue;
    }
//printf("multiline.in=#%s#\n",str->getString());
//printf("XXXXXXXXXXXXXXXXXXZZZZZZZZZZ start\n");
    WSCstring lstr;
    lstr = str->gets();
//printf("XXXXXXXXXXXXXXXXXXZZZZZZZZZZ done\n");
//printf("WSDxdraw::drawUString:\n%s\n",lstr.getString(WS_EN_EUCJP));

//printf("multiline lstr=#%s#\n",lstr.getString(WS_EN_EUCJP));
    lpos += prelpos;
    prelpos = lstr.getChars() +1;
    if ((long)(cly + clh) < points[i].y){
      break;
    }
    char* tstr;
//    if (WSGIappLocaleSet()->getDefaultEncoding() == WS_EN_EUCJP){
//      tstr = lstr.getString(WS_EN_EUCJP);
//    }else{
      tstr = lstr.getString(WS_EN_UTF8);
//    }
//printf("multiline...#%s#\n",tstr);
    if (cur == -1){
      WSGFxdrawTextString( _display, _window, _gc, efs, kfs, gfs, _fg_color,
        _bg_color,points[i].x, points[i].y + fheight,
        tstr, kfontWidth, efontWidth, fheight2,fheight, -1,
        inter_cur,_line_width,
        scur1 - lpos,scur2 - lpos);
//printf("cur=%d c1=%d c2=%d  lpos=%d pre=%d\n",-1,scur1-lpos,scur2-lpos,lpos,prelpos);
    }else{
      WSGFxdrawTextString( _display, _window, _gc, efs, kfs, gfs, _fg_color,
        _bg_color,points[i].x, points[i].y + fheight,
        tstr, kfontWidth, efontWidth, fheight2,fheight,cur - lpos,
        inter_cur,_line_width,
        scur1 - lpos,scur2 - lpos);
//printf("cur=%d c1=%d c2=%d  lpos=%d pre=%d\n",cur-lpos,scur1-lpos,scur2-lpos,lpos,prelpos);
    }
  }
  str->seek(0);
  if (num != 0){
    delete points;
  }
  setRegion(clx_bk,cly_bk,clw_bk,clh_bk);

#ifdef TDBG
  printf("WSDxdraw::drawString done %d\n",WSGFclocktime());
#endif

  return WS_NO_ERR;
}

long WSDxdraw::drawFillString(long x,long y,WSCulong w,WSCulong h,
           WSCstring* str,char font,char align,short cur,WSCbool inter_cur){

  if (_gc == 0 || _window == 0){
    return WS_ERR;
  }
  short clx_bk = _clip_x;
  short cly_bk = _clip_y;
  WSCushort clw_bk = _clip_w;
  WSCushort clh_bk = _clip_h;
  long clx,cly;
  WSCulong clw,clh;
  WSGFandArea(x,y,w,h,_clip_x,_clip_y,_clip_w,_clip_h,&clx,&cly,&clw,&clh);
  setRegion(clx,cly,clw,clh);

  XSetForeground(_display,_gc,_bg_color);
  XFillRectangle(_display,_window,_gc,(int)x,(int)y,(WSCuint)w-1,(WSCuint)h-1); 
  XSetForeground(_display,_gc,_fg_color);

  WSDfont* fn = WSGIappFontSet()->getFont(font);
  if (fn == NULL){
    fn = WSGIappFontSet()->getDefaultFont();
    if (fn == NULL){
      return WS_ERR;
    }
  }
  XFontStruct* efs = (XFontStruct*)fn->getValue1();
  XFontStruct* kfs = (XFontStruct*)fn->getValue2();
  XFontStruct* gfs = (XFontStruct*)fn->getValue3();
  long efontWidth = 14;
  long kfontWidth = 14;
  Font efid;
  if (efs == NULL || efs == (void*)-1){
    return WS_ERR;
  }else{
    efid = efs->fid;
    efontWidth = (long)efs->max_bounds.rbearing;
  }
  Font kfid;
  if (kfs == NULL || kfs == (void*)-1){
    kfid = efid;
    kfontWidth = efontWidth;
  }else{
    kfid = kfs->fid;
    kfontWidth = (long)kfs->max_bounds.rbearing;
  }
  Font gfid;
  if (gfs == NULL || gfs == (void*)-1){
    gfid = efid;
  }else{
    gfid = gfs->fid;
  }
  long fheight = (long)efs->max_bounds.ascent;
  long fheight2 = (long)kfs->max_bounds.ascent;
  if (str->isExist("\n") == -1){
    WSCrect area;
    area.setRect(x,y,w,h);
    WSCpoint  point;
    WSGFcalcOneLineStringAddr(str,&area,align,fn,&point);
//    char* tstr = str->getEucString();
    char* tstr = str->getString(WS_EN_UTF8);
    char* tstr2 = new char[strlen(tstr) + 8];
    strcpy(tstr2,tstr);
    strcat(tstr2," ");

    WSGFxdrawTextString( _display, _window, _gc, efs, kfs, gfs, _fg_color,
      _bg_color,point.x, point.y + fheight,
      tstr2, kfontWidth, efontWidth, fheight2, fheight, cur, inter_cur,_line_width);
    delete tstr2;
    setRegion(clx_bk,cly_bk,clw_bk,clh_bk);
    return WS_NO_ERR;
  }

  long num;
  WSCrect   area;
  area.setRect(x,y,w,h);
  WSCpoint* points;
  WSGFcalcStringAddr(str,&area,align,fn,&points,&num);
  long i;
  str->seek(0);
  long lpos =0;
  long prelpos =0;
  for(i=0; i < num; i++){
    if ((long)(points[i].y + fheight) < cly ||  (long)(cly + clh) < (long)points[i].y){
      lpos += prelpos;
      prelpos = str->_seek_next_line() +1;
      continue;
    }

    WSCstring lstr;
    lstr = str->gets();
    lpos += prelpos;
    prelpos = lstr.getChars() +1;

//    char* tstr = lstr.getEucString();
    char* tstr = lstr.getString(WS_EN_UTF8);
    char* tstr2 = new char[strlen(tstr) + 8];
    strcpy(tstr2,tstr);
//    strcat(tstr2," ");
    WSGFxdrawTextString( _display, _window, _gc, efs, kfs, gfs, _fg_color,
       _bg_color,points[i].x, points[i].y + fheight,
       tstr2, kfontWidth, efontWidth, fheight2, fheight, cur - lpos, inter_cur,_line_width);
    delete tstr2;
  }
  str->seek(0);
  if (num != 0){
    delete points;
  }
  setRegion(clx_bk,cly_bk,clw_bk,clh_bk);
  return WS_NO_ERR;
}

extern WSCulong WSGFxcolorval(WSDcolor*,WSCuchar,WSCuchar,WSCuchar);

long WSDxdraw::drawGradation(long type,short c1,short c2,short c3,
                  short x,short y,WSCushort w,WSCushort h,WSCuchar gradm){

static WSDcolor* color = NULL;
  if (_gc == 0 || _window == 0){
    return WS_ERR;
  }
  short clx_bk = _clip_x;
  short cly_bk = _clip_y;
  WSCushort clw_bk = _clip_w;
  WSCushort clh_bk = _clip_h;
  long clx,cly;
  WSCulong clw,clh;
  WSGFandArea(x,y,w,h,_clip_x,_clip_y,_clip_w,_clip_h,&clx,&cly,&clw,&clh);
  setRegion(clx,cly,clw,clh);

  WSDcolor* col1 = WSGIappColorSet()->getColor(c1);
  WSDcolor* col2 = WSGIappColorSet()->getColor(c2);
  WSDcolor* col3 = WSGIappColorSet()->getColor(c3);
  long r1,g1,b1;
  long r2,g2,b2;
  long r3,g3,b3;
  if (col1 == NULL || col2 == NULL || col3 == NULL){
    setRegion(clx_bk,cly_bk,clw_bk,clh_bk);
    return WS_ERR;
  }
  fgcolor = -100;
  bgcolor = -100;
  _fg_color = 0;
  _bg_color = 0;
  _fg_color_no = 0xffffffff;
  _bg_color_no = 0xffffffff;

  long display_depth = XDefaultDepth(_display,XDefaultScreen(_display));
  if (display_depth < 9){
    WSCulong cval1 = (WSCulong )col2->getValue1();
    XSetForeground(_display,_gc,cval1);
    XFillRectangle(_display,_window,_gc,(int)x,(int)y,(WSCuint)w,(WSCuint)h); 
    setRegion(clx_bk,cly_bk,clw_bk,clh_bk);
    return WS_NO_ERR;
  }

  col1->getRGB(&r1,&g1,&b1);
  col2->getRGB(&r2,&g2,&b2);
  col3->getRGB(&r3,&g3,&b3);
  color = WSGIappColorSet()->getColor((short)0);
  if (color == NULL){
    color = WSGIappColorSet()->getNewColor();
    color->setId(0);
    color->setUsePrivateCell(True);
    WSGIappColorSet()->addColor(color);
  }
  if (gradm != 0){
    WSCulong cval1 = (WSCulong )col2->getValue1();
    XSetForeground(_display,_gc,cval1);
    XFillRectangle(_display,_window,_gc,(int)x,(int)y,(WSCuint)w,(WSCuint)h); 
  }
  long i;
  if (type == WS_GR_LT_RB || type == WS_GR_RB_LT){
    long max = (w+h)* (100 -gradm)/100;
    long wval = max/64+1;
    XSetLineAttributes(_display,_gc,wval+1,LineSolid,CapProjecting,WS_JOIN);
    for(i=0; i<max;i+=wval){
      long x1 = x +i;
      long y1 = y +i;
      if (i > max/2){ 
        x1 = x + (w+h)*gradm/100 + i;
        y1 = y + (w+h)*gradm/100 + i;
      }
      if (_clip_y != -1){
        if (_clip_y > -_clip_x + y1 + x || _clip_y + _clip_h < -_clip_x - _clip_w + y1 + x){
//          continue;
        }
      }
      long val1,val2,val3;
      if (type == WS_GR_LT_RB){
        if (i < max/2){ 
          val1 = (r1 * (max -i*2)  + r2 * i *2) /max;
          val2 = (g1 * (max -i*2)  + g2 * i *2) /max;
          val3 = (b1 * (max -i*2)  + b2 * i *2) /max;
        }else{ 
          val1 = (r2 * (max *2 -i*2)  + r3 * (i *2 -max)) /max;
          val2 = (g2 * (max *2 -i*2)  + g3 * (i *2 -max)) /max;
          val3 = (b2 * (max *2 -i*2)  + b3 * (i *2 -max)) /max;
        }
      }else{
        if (i < max/2){ 
          val1 = (r3 * (max -i*2)  + r2 * i *2) /max;
          val2 = (g3 * (max -i*2)  + g2 * i *2) /max;
          val3 = (b3 * (max -i*2)  + b2 * i *2) /max;
        }else{ 
          val1 = (r2 * (max *2 -i*2)  + r1 * (i *2 -max)) /max;
          val2 = (g2 * (max *2 -i*2)  + g1 * (i *2 -max)) /max;
          val3 = (b2 * (max *2 -i*2)  + b1 * (i *2 -max)) /max;
        }
      }
      if (val1 < 0){
        val1 = 0;
      }
      if (val2 < 0){
        val2 = 0;
      }
      if (val3 < 0){
        val3 = 0;
      }
      if (val1 > 0xff){
        val1 = 0xff;
      }
      if (val2 > 0xff){
        val2 = 0xff;
      }
      if (val3 > 0xff){
        val3 = 0xff;
      }
      
      WSCulong cval = WSGFxcolorval(color,val1,val2,val3);
      XSetForeground(_display,_gc,cval);
      XDrawLine(_display,_window,_gc,(int)x1,(int)y,(int)x,(int)y1); 
    }
  }else
  if (type == WS_GR_LB_RT || type == WS_GR_RT_LB){
    long max = (w+h)* (100 -gradm)/100;
    long wval = max/64+1;
    XSetLineAttributes(_display,_gc,wval+1,LineSolid,CapProjecting,WS_JOIN);
    for(i=0; i<max;i+=wval){
      long x1 = x +i;
      long y1 = y +h -i;
      if (i >= max/2){
        x1 = x +i + (w+h) * gradm/100;
        y1 = y +h -i - (w+h) * gradm/100;
      }
      if (_clip_y != -1){
        if (_clip_y > _clip_x + _clip_w + y1 - x || _clip_y + _clip_h < _clip_x + y1 - x){
//          continue;
        }
      }
      long val1,val2,val3;
      if (type == WS_GR_LB_RT){
        if (i < max/2){ 
          val1 = (r1 * (max -i*2)  + r2 * i *2) /max;
          val2 = (g1 * (max -i*2)  + g2 * i *2) /max;
          val3 = (b1 * (max -i*2)  + b2 * i *2) /max;
        }else{ 
          val1 = (r2 * (max *2 -i*2)  + r3 * (i *2 -max)) /max;
          val2 = (g2 * (max *2 -i*2)  + g3 * (i *2 -max)) /max;
          val3 = (b2 * (max *2 -i*2)  + b3 * (i *2 -max)) /max;
        }
      }else{
        if (i < max/2){ 
          val1 = (r3 * (max -i*2)  + r2 * i *2) /max;
          val2 = (g3 * (max -i*2)  + g2 * i *2) /max;
          val3 = (b3 * (max -i*2)  + b2 * i *2) /max;
        }else{ 
          val1 = (r2 * (max *2 -i*2)  + r1 * (i *2 -max)) /max;
          val2 = (g2 * (max *2 -i*2)  + g1 * (i *2 -max)) /max;
          val3 = (b2 * (max *2 -i*2)  + b1 * (i *2 -max)) /max;
        }
      }
      if (val1 < 0){
        val1 = 0;
      }
      if (val2 < 0){
        val2 = 0;
      }
      if (val3 < 0){
        val3 = 0;
      }
      if (val1 > 0xff){
        val1 = 0xfff;
      }
      if (val2 > 0xff){
        val2 = 0xff;
      }
      if (val3 > 0xff){
        val3 = 0xff;
      }
      WSCulong cval = WSGFxcolorval(color,val1,val2,val3);
      XSetForeground(_display,_gc,cval);
      XDrawLine(_display,_window,_gc,(int)x,(int)y1,(int)x1,(int)(y+h)); 
    }
  }else
  if (type == WS_GR_T_B || type == WS_GR_B_T){
    long max = h* (100 -gradm)/100;
    long wval = max/64+1;
    XSetLineAttributes(_display,_gc,wval+1,LineSolid,CapProjecting,WS_JOIN);
    for(i=0; i<max;i+=wval){
      long h1 = i;
      if (h1 >= max/2){
        h1 = i+ h * gradm/100;
      }
      if (_clip_x != -1){
        if (_clip_y > h1+y || _clip_y + _clip_h < h1+y){
//          continue;
        }
      }
      long val1,val2,val3;
      if (type == WS_GR_T_B){
        if (i < max/2){ 
          val1 = (r1 * (max -i*2)  + r2 * i *2) /max;
          val2 = (g1 * (max -i*2)  + g2 * i *2) /max;
          val3 = (b1 * (max -i*2)  + b2 * i *2) /max;
        }else{ 
          val1 = (r2 * (max*2 -i*2)  + r3 * (i *2 -max)) /max;
          val2 = (g2 * (max*2 -i*2)  + g3 * (i *2 -max)) /max;
          val3 = (b2 * (max*2 -i*2)  + b3 * (i *2 -max)) /max;
        }
      }else{
        if (i < max/2){ 
          val1 = (r3 * (max -i*2)  + r2 * i *2) /max;
          val2 = (g3 * (max -i*2)  + g2 * i *2) /max;
          val3 = (b3 * (max -i*2)  + b2 * i *2) /max;
        }else{ 
          val1 = (r2 * (max*2 -i*2)  + r1 * (i *2 -max)) /max;
          val2 = (g2 * (max*2 -i*2)  + g1 * (i *2 -max)) /max;
          val3 = (b2 * (max*2 -i*2)  + b1 * (i *2 -max)) /max;
        }
      }
      if (val1 < 0){
        val1 = 0;
      }
      if (val2 < 0){
        val2 = 0;
      }
      if (val3 < 0){
        val3 = 0;
      }
      if (val1 > 0xff){
        val1 = 0xff;
      }
      if (val2 > 0xff){
        val2 = 0xff;
      }
      if (val3 > 0xff){
        val3 = 0xff;
      }
      WSCulong cval = WSGFxcolorval(color,val1,val2,val3);
      XSetForeground(_display,_gc,cval);
      XDrawLine(_display,_window,_gc,(int)x,(int)(y+h1),(int)(x+w),(int)(y+h1)); 
    }
  }else{
    long max = w* (100 -gradm)/100;
    long wval = max/64+1;
    XSetLineAttributes(_display,_gc,wval+1,LineSolid,CapProjecting,WS_JOIN);
    for(i=0; i<max; i+=wval){
      long w1 = i;
      if (w1 >= max/2){
        w1 = i+ w * gradm/100;
      }
      if (_clip_x != -1){
        if (_clip_x > w1+x || _clip_x + _clip_w < w1+x){
//          continue;
        }
      }
      long val1,val2,val3;
      if (type == WS_GR_L_R){
        if (i < max/2){ 
          val1 = (r1 * (max -i*2)  + r2 * i *2) /max;
          val2 = (g1 * (max -i*2)  + g2 * i *2) /max;
          val3 = (b1 * (max -i*2)  + b2 * i *2) /max;
        }else{ 
          val1 = (r2 * (max*2 -i*2)  + r3 * (i *2 -max)) /max;
          val2 = (g2 * (max*2 -i*2)  + g3 * (i *2 -max)) /max;
          val3 = (b2 * (max*2 -i*2)  + b3 * (i *2 -max)) /max;
        }
      }else{
        if (i < max/2){ 
          val1 = (r3 * (max -i*2)  + r2 * i *2) /max;
          val2 = (g3 * (max -i*2)  + g2 * i *2) /max;
          val3 = (b3 * (max -i*2)  + b2 * i *2) /max;
        }else{ 
          val1 = (r2 * (max*2 -i*2)  + r1 * (i *2 -max)) /max;
          val2 = (g2 * (max*2 -i*2)  + g1 * (i *2 -max)) /max;
          val3 = (b2 * (max*2 -i*2)  + b1 * (i *2 -max)) /max;
        }
      }
      if (val1 < 0){
        val1 = 0;
      }
      if (val2 < 0){
        val2 = 0;
      }
      if (val3 < 0){
        val3 = 0;
      }
      if (val1 > 0xff){
        val1 = 0xff;
      }
      if (val2 > 0xff){
        val2 = 0xff;
      }
      if (val3 > 0xff){
        val3 = 0xff;
      }
      WSCulong cval = WSGFxcolorval(color,val1,val2,val3);
      XSetForeground(_display,_gc,cval);
      XDrawLine(_display,_window,_gc,(int)(w1+x),(int)y,(int)(w1+x),(int)y+h); 
    }
  }
  long linet = _line_type;
  _line_type = -1;
  setLineDashType(linet);
  setRegion(clx_bk,cly_bk,clw_bk,clh_bk);

  return WS_NO_ERR;
}

