#include <stdlib.h>
#include <stdio.h>

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>
#include <X11/IntrinsicP.h>
#include <X11/Shell.h>
#include <X11/Core.h>
#include <X11/CoreP.h>

#include <X11/keysym.h>

#include <Xm/Xm.h>       // A cause des container XmForm 
#include <Xm/Form.h>     // Idem 

#include "sopnamsp.h"
#include "piwdgx.h"
#include "picontainerx.h"
#include "pievthandler.h"
#include "pigraphx.h"

#include "pexceptions.h"


// #define DEBUG_PIWdgX

// Quelques variables statiques globales, Connection Display, Top Widget Xt, AppContext Xt ...
// et leurs fonctions d'acces 
static SysDWdg  top = NULL;
static Display * dpy = NULL;
static GC defgc;
// static char appname[64];
static char appclass[64];
static XtAppContext appctx;
static int appSzX = 10;
static int appSzY = 10;
static int appSzFont = 10;
static XFontStruct * stdfnt = NULL;

// Variable globale Widget qui possede la selection pour le copier-coller
static PIWdgX* curselwdg = NULL;    // Le PIWdg qui possede la selection

/* Nouvelle-Fonction */
XtAppContext* PIXtAppCtx(int& szx, int& szy, int& szf)
{
szx = appSzX;  szy = appSzY;
szf = appSzFont;
return(&appctx);
}

/* Nouvelle-Fonction */
SysDWdg   PIXtTopWdg()
{
return (top);
}

/* Nouvelle-Fonction */
Display * PIXDisplay()
{
return(dpy);
}

/* Nouvelle-Fonction */
void PIBeep()
{
XBell(dpy, 0);
return;
}

/* Nouvelle-Fonction */
int CStrFrXmStr(XmString xms, char* buff, int nmx)
/*  Pour recuperer le contenu d'un string Motif  */
{
int n,l,m;
XmStringContext cntx;
char *txs;
XmStringDirection dir;
XmStringCharSet cset;
Boolean sep;

if (nmx < 2)  return(0);
n = 0;  m = nmx-1;  buff[0] = buff[m] = '\0';
XmStringInitContext (&cntx, xms);
while (m > 0)
  {
  if (XmStringGetNextSegment( cntx, &txs, &cset, &dir, &sep) )
    {
    l = strlen(txs);
    if (m < l)  txs[m] = '\0';
    strcpy(buff+n, txs);
    n += l;   m -= l;
    if (sep)  m = -2;
    XtFree(txs);
    }
  else m = -1;
  }

return(n);
} 


/* --Methode-- */
PIWdgX::PIWdgX(int narg, char *arg[])
:PIWdgGen(NULL, "PITopLevel")  
{
if (top == NULL)  InitXt(narg, arg);
sdw = top;
wmis =  k_wmi_appshell;
stmng = false;
finishDone = false;
mFCol = mBCol = PI_NotDefColor;
mBKleft =  mBKright =  mBKtop =  mBKbottom = PIBK_free;
#ifdef DEBUG_PIWdgX
printf("Debug_PIWdgX::PIWdgX(int , char * [])  this=%lx  top=%lx \n", (long)this, (long)sdw);
#endif
}



/* --Methode-- */
PIWdgX::PIWdgX(PIContainerGen *par, const char *nom, 
               int sx, int sy, int px, int py)
:PIWdgGen(par, nom, sx, sy, px, py) 
{
sdw = NULL;
wmis = k_wmi_unknown;
finishDone = false;
mFCol = mBCol = PI_NotDefColor;
mBKleft =  mBKright =  mBKtop =  mBKbottom = PIBK_free;
}

/* --Methode-- */
int PIWdgX::CreateXtWdg(const char *nom, SysDWdgClass wdgcl, SysDWdg pwdg,
                        int sx, int sy, int px, int py, Arg* oarg, int na)
{
Arg  wargs[20];
int n=0;

#ifdef DEBUG_PIWdgX
if (nom) printf("Debug_PIWdgX::CreateXtWdg(%s) Getting in \n", nom);
else printf("Debug_PIWdgX::CreateXtWdg(NULL) Getting in \n");
#endif

if (pwdg == NULL)
  {
  if (parent == NULL)
    {
    if (top == NULL)  InitXt();
    pwdg = top;
    }
  // else pwdg = ((PIContainerX *)parent)->sdw;
  else pwdg = ((PIWdgX *)parent)->sdw;
  }

n=0;
if ((sx >= 0) && (sy >= 0))
  {
  XtSetArg(wargs[n],XtNwidth,sx);  n++;
  XtSetArg(wargs[n],XtNheight,sy);  n++;
  }
XtSetArg(wargs[n],XtNx,px);  n++;
XtSetArg(wargs[n],XtNy,py);  n++;

if (na > 16) { printf("PIWdgX::CreateXtWdg()/Warning: na=%d > Max=16 \n", na);  na = 16; }
for(int kk=0; kk<na; kk++) { wargs[n] = oarg[kk]; n++; }

if (wdgcl == NULL)  wdgcl = coreWidgetClass;

if ( (wdgcl == topLevelShellWidgetClass) || 
     (wdgcl == transientShellWidgetClass) ||
     (wdgcl == overrideShellWidgetClass) )
  {
  sdw = XtCreatePopupShell(nom, wdgcl, pwdg, wargs, n);
  }
else
  {
  sdw = XtCreateWidget(nom, wdgcl, pwdg, wargs, n);
  }

if (wdgcl == topLevelShellWidgetClass)  wmis = k_wmi_toplevel;
else if (wdgcl == transientShellWidgetClass)  wmis = k_wmi_transient;
else if (wdgcl == overrideShellWidgetClass)  wmis = k_wmi_override;
else wmis = k_wmi_normal ;

stmng = false;
#ifdef DEBUG_PIWdgX
printf("Debug_PIWdgX::CreateXtWdg(%s) this=%lx sdw=%lx pere=%lx wmis=%d\n", nom, 
       (long)this, (long)sdw, (long)pwdg, wmis);
#endif
mFCol = mBCol = PI_NotDefColor;
SetBinding(PIBK_free, PIBK_free, PIBK_free, PIBK_free);
if (parent) parent->ChildAdd(this);
return(0);
}


/* --Methode-- */
PIWdgX::~PIWdgX()
{
#ifdef DEBUG_PIWdgX
printf("Debug_PIWdgX::~PIWdgX()  %lx %lx \n", (long)this, (long)sdw);
#endif
if (parent) parent->ChildDel(this);
UnManage();
if (curselwdg == this)  { SelectionLost(); curselwdg = NULL; }
if (sdw)  { 
// Pour gerer la double structure en Widget des PIWindowX
  if (wmis == k_wmi_normal) XtDestroyWidget(sdw);
  else if (wmis == k_wmi_cascade) { 
    SysDWdg pwdg = XtParent(sdw);
    XtDestroyWidget(sdw);
    if (pwdg) XtDestroyWidget(pwdg);
    }
  }
}


/* --Methode-- */
void PIWdgX::FinishCreate()
{
// appele par la fenetre mere, apres XtRealize()
// Doit pouvoir etre appele plusieurs fois
finishDone = true;
return;
}


/* --Methode-- */
void PIWdgX::Manage()
{
#ifdef DEBUG_PIWdgX
printf("Debug_PIWdgX::Manage  this=%lx  sdw=%lx \n", (long)this, (long)sdw);
#endif
if (!sdw)  return;
if (wmis != k_wmi_appshell)  XtManageChild(sdw);
else if (!XtIsRealized(sdw))  XtRealizeWidget(sdw);  
stmng = true;
return;
}

/* --Methode-- */
void PIWdgX::UnManage()
{
#ifdef DEBUG_PIWdgX
printf("Debug_PIWdgX::UnManage  this=%lx sdw=%lx \n", (long)this, (long)sdw);
#endif
if (!sdw)  return;
if (wmis != k_wmi_appshell) 
  XtUnmanageChild(sdw);
stmng = false;
return;
}

/* --Methode-- */
bool PIWdgX::IfManaged()
{
return(stmng);
}

/* --Methode-- */
bool PIWdgX::IsVisible()
{
if ( (XtIsRealized(XtWdg())) &&  
   ( (this->XtWdg())->core.visible) )  return(true);
else return(false);       
}

/* --Methode-- */
void PIWdgX::Refresh()
{
if (XtIsRealized(XtWdg()))
  XClearArea(XtDisplay(XtWdg()), XtWindow(XtWdg()), 0, 0, 0, 0, True);
}

/* --Methode-- */
void PIWdgX::SetSensitive()
{
XtSetSensitive(XtWdg(), TRUE);
}

/* --Methode-- */
void PIWdgX::SetUnSensitive()
{
XtSetSensitive(XtWdg(), FALSE);
}

/* --Methode-- */
bool PIWdgX::IfSensitive()
{
if (XtIsSensitive(XtWdg()) == TRUE)  return(true);
else return(false);
}

/* --Methode-- */
void PIWdgX::SetSize(int sx, int sy)
{
#ifdef DEBUG_PIWdgX
printf("Debug_PIWdgX::SetSize  this=%lx  sdw=%lx \n", (long)this, (long)sdw);
#endif

if (!sdw)  return;
/*
Arg  wargs[2];
XtSetArg(wargs[0],XtNwidth,sx); 
XtSetArg(wargs[1],XtNheight,sy); 
XtSetValues(this->sdw, wargs, 2);
*/
/*  Modifs Reza Avril 2007, remplacement par XtMakeGeometryRequest 
XtResizeWidget(sdw, sx, sy, BorderWidth());
*/
XtWidgetGeometry wgeom;
wgeom.request_mode = CWWidth|CWHeight;
wgeom.width = sx;
wgeom.height = sy;
XtMakeGeometryRequest(sdw, &wgeom, NULL);
return;
} 

/* --Methode-- */
void PIWdgX::SetPos(int px, int py)
{
if (!sdw)  return;
/*
Arg  wargs[2];
XtSetArg(wargs[0],XtNx,px);  
XtSetArg(wargs[1],XtNy,py);  
XtSetValues(this->sdw, wargs, 2);
*/
/*  Modifs Reza Avril 2007, remplacement par XtMakeGeometryRequest 
XtMoveWidget(sdw, px, py);
*/
XtWidgetGeometry wgeom;
wgeom.request_mode = CWX|CWY;
wgeom.x = px;
wgeom.y = py;
XtMakeGeometryRequest(sdw, &wgeom, NULL);
return;
} 

/* --Methode-- */
void PIWdgX::SetBackgroundColor(PIColors col)
{
if (col < 0)  return;
Arg  wargs[2];
XtSetArg(wargs[0],XtNbackground, PIGraphicX::GetPixelValueforColor(col) );  
XtSetValues(XtWdg(), wargs, 1);
mBCol = col;
return;
}

/* --Methode-- */
void PIWdgX::SetForegroundColor(PIColors col)
{
if (col < 0)  return;
Arg  wargs[2];
XtSetArg(wargs[0],XtNforeground, PIGraphicX::GetPixelValueforColor(col) );  
XtSetValues(XtWdg(), wargs, 1);
mFCol = col;
return;
}

/* --Methode-- */
void PIWdgX::EraseWindow(int x0, int y0, int dx, int dy)
{
XClearArea (XtDisplay(XtWdg()),XtWindow(XtWdg()), x0, y0, dx, dy, False );
return;
}

/* --Methode-- */
PIColors   PIWdgX::GetBackgroundColor()
{
return(mBCol);
}

/* --Methode-- */
PIColors   PIWdgX::GetForegroundColor()
{
return(mFCol);
}

 
/* --Methode-- */
void PIWdgX::SetBinding(PIBindingKind left, PIBindingKind top, 
                        PIBindingKind right, PIBindingKind bottom)
{
if (bindingLock) return;
mBKleft = left;  mBKright = right;
mBKtop = top;  mBKbottom = bottom;
BindWdgtoParent();
}


/* *** ATTENTION *** La constante ci-dessous PIXMFORMFRACBASE
   doit etre identique ds piwdgx.cc  picontainerx.cc et piwindowx.cc
   ***************************************************************** */
#define PIXMFORMFRACBASE 1000

/* --Methode-- */
void PIWdgX::BindWdgtoParent()
{
if (bindingLock) return;
if (!sdw)  return;
if (!parent)  return;


PIBindingKind left, top, right, bottom;
left = mBKleft;  right = mBKright;
top = mBKtop;  bottom = mBKbottom;

int fbase = PIXMFORMFRACBASE ;  // Valeur de XmNfractionBase des XmForm ds PIContainerX
int frpos = 0;
float frac;
Arg  wargs[13];
int n=0;

// printf(" DEBUG_SetBinding: C-Sz= %d %d - Sz=%d %d , Pos= %d %d \n",  parent->XSize(),
// parent->YSize(), XSize(), YSize(), XPos(), YPos());
switch (left)
  {
  case PIBK_free : 
    XtSetArg(wargs[n],XmNleftAttachment, XmATTACH_NONE);  n++;
    break;
  case PIBK_fixed :
    XtSetArg(wargs[n],XmNleftAttachment, XmATTACH_FORM);  n++;
    XtSetArg(wargs[n],XmNleftOffset, XPos() );  n++;
    break;
  case PIBK_elastic :
    XtSetArg(wargs[n],XmNleftAttachment, XmATTACH_POSITION);  n++;
    frac = (float)(XPos())/(float)parent->XSize() ;
    frpos = frac*fbase;
    XtSetArg(wargs[n],XmNleftPosition, frpos );  n++;
    XtSetArg(wargs[n],XmNleftOffset, 0 );  n++;
    break;
  default :
    left = PIBK_free;
    XtSetArg(wargs[n],XmNleftAttachment, XmATTACH_NONE);  n++;
    break;    
  }
 
switch (top)
  {
  case PIBK_free : 
    XtSetArg(wargs[n],XmNtopAttachment, XmATTACH_NONE);  n++;
    break;
  case PIBK_fixed :
    XtSetArg(wargs[n],XmNtopAttachment, XmATTACH_FORM);  n++;
    XtSetArg(wargs[n],XmNtopOffset, YPos() );  n++;
    break;
  case PIBK_elastic :
    XtSetArg(wargs[n],XmNtopAttachment, XmATTACH_POSITION);  n++;
    frac = (float)(YPos())/(float)parent->YSize() ;
    frpos = frac*fbase;
    XtSetArg(wargs[n],XmNtopPosition, frpos );  n++;
    XtSetArg(wargs[n],XmNtopOffset, 0 );  n++;
    break;
  default :
    top = PIBK_free;
    XtSetArg(wargs[n],XmNtopAttachment, XmATTACH_NONE);  n++;
    break;
  }
  
switch (right) 
  {
  case PIBK_free : 
    XtSetArg(wargs[n],XmNrightAttachment, XmATTACH_NONE);  n++;
    break;
  case PIBK_fixed :
    XtSetArg(wargs[n],XmNrightAttachment, XmATTACH_FORM);  n++;
    XtSetArg(wargs[n],XmNrightOffset, parent->XSize()-(XSize()+XPos()) );  n++;
    break;
  case PIBK_elastic :
    XtSetArg(wargs[n],XmNrightAttachment, XmATTACH_POSITION);  n++;
    frac = (float)(XPos()+XSize())/(float)parent->XSize() ;
    frpos = frac*fbase;
    XtSetArg(wargs[n],XmNrightPosition, frpos );  n++;
    XtSetArg(wargs[n],XmNrightOffset, 0 );  n++;
    break;
  default : 
    right = PIBK_free;
    XtSetArg(wargs[n],XmNrightAttachment, XmATTACH_NONE);  n++;
    break;

  }

switch (bottom) 
  {
  case PIBK_free : 
    XtSetArg(wargs[n],XmNbottomAttachment, XmATTACH_NONE);  n++;
    break;
  case PIBK_fixed :
    XtSetArg(wargs[n],XmNbottomAttachment, XmATTACH_FORM);  n++;
    XtSetArg(wargs[n],XmNbottomOffset, parent->YSize()-(YSize()+YPos()) );  n++;
    break;
  case PIBK_elastic :
    XtSetArg(wargs[n],XmNbottomAttachment, XmATTACH_POSITION);  n++;
    frac = (float)(YPos()+YSize())/(float)parent->YSize() ;
    frpos = frac*fbase;
    XtSetArg(wargs[n],XmNbottomPosition, frpos );  n++;
    XtSetArg(wargs[n],XmNbottomOffset, 0 );  n++;
    break;
  default :
    bottom =  PIBK_free;
    XtSetArg(wargs[n],XmNbottomAttachment, XmATTACH_NONE);  n++;
    break;
  }

// Widget bwd = (XtParent(this->sdw) == parent->XtWdg()) ? this->sdw : XtParent(this->sdw);
XtSetValues(this->sdw, wargs, n);
// printf(" Out_SetBinding: C-Sz= %d %d - Sz=%d %d , Pos= %d %d \n",  parent->XSize(),
// parent->YSize(), XSize(), YSize(), XPos(), YPos());

return;
}

/* --Methode-- */
bool PIWdgX::GetBinding(PIBindingKind& left, PIBindingKind& top, 
                        PIBindingKind& right, PIBindingKind& bottom)
{
left = mBKleft;  right = mBKright;
top = mBKtop;  bottom = mBKbottom;
return(bindingLock);
}

/* --Methode-- */
void PIWdgX::SetBorderWidth(int bw)
{
if (!sdw)  return;

Arg  wargs[2];
int n=0;

XtSetArg(wargs[n],XtNborderWidth,bw);  n++;
XtSetValues(this->sdw, wargs, n);
return;
}


/* --Methode-- */
int PIWdgX::XSize()
{
if (!sdw)  return(-1);
else return((int)this->sdw->core.width);
}

/* --Methode-- */
int PIWdgX::YSize()
{
if (!sdw)  return(-1);
else return((int)this->sdw->core.height);
}

/* --Methode-- */
int PIWdgX::XPos()
{
if (!sdw)  return(-1);
else return((int)this->sdw->core.x);
}

/* --Methode-- */
int PIWdgX::YPos()
{
if (!sdw)  return(-1);
else return((int)this->sdw->core.y);
}


/* --Methode-- */
int PIWdgX::BorderWidth()
{
if (!sdw)  return(-1);
Arg  wargs[2];
int bw;
XtSetArg(wargs[0],XtNborderWidth, &bw);  
XtGetValues(this->sdw, wargs, 1);
return(bw);
}

/* --Methode-- */
string PIWdgX::Nom()
{
return(XtName(this->sdw));
}

/* --Methode-- */
void PIWdgX::GetScreenPos(int & spx, int & spy)
{
PIWdgX * wc;
Display *mdsp;
Window w, rw, pw, *cw;
unsigned int ncw;
Status st;
int x,y;
unsigned int bw, l, h, d;

spx = 0;  spy = 0;
wc = this;

while (wc)
  { spx += wc->XPos();
  spy += wc->YPos();  wc = (PIWdgX *)wc->Parent();
  }

mdsp = XtDisplay(XtWdg());
w = XtWindow(XtWdg());
ncw = 0;
st = XQueryTree(mdsp, w, &rw, &pw, &cw, &ncw);
if (st) 
  { XFree(cw);
  if (pw == rw)  return; }

while (st && (pw != rw))  
  {
  w = pw;
  st = XQueryTree(mdsp, w, &rw, &pw, &cw, &ncw); 
  if (st)   XFree(cw);
  XGetGeometry(mdsp, w, &rw, &x, &y, &l, &h, &bw, &d);  
  spy += y;  spx += x;
  }  
return;
}


// Ressources X si non definis 
static const String fallback_res[26] = {
const_cast<char*>("PeidaInt*default*background:                 LightGrey") ,
const_cast<char*>("PeidaInt*background:                         LightGrey") ,
const_cast<char*>("PeidaInt*Foreground:                         Black"),
const_cast<char*>("PeidaInt*default*Foreground:                 Black"),
const_cast<char*>("PeidaInt*default*bottomShadowColor:          Black"),
const_cast<char*>("PeidaInt*bottomShadowColor:                  Black"),
const_cast<char*>("PeidaInt*default*topShadowColor:             White"),
const_cast<char*>("PeidaInt*topShadowColor:                     White"),
const_cast<char*>("PeidaInt*borderColor:                        Black"),
const_cast<char*>("PeidaInt*XmLabel.borderWidth:                0"),
const_cast<char*>("PeidaInt*XmDrawingArea*background:           Black"),
const_cast<char*>("PeidaInt*XmPushButton*borderWidth:           0"),
const_cast<char*>("PeidaInt*XmText*shadowThickness:             2"),
const_cast<char*>("PeidaInt*XmText*highlightThickness:          0"),
const_cast<char*>("PeidaInt*XmText*marginHeigt:                 0"),
const_cast<char*>("PeidaInt*XmText*marginWidth:                 2"),
// const_cast<char*>("PeidaInt*DefMenubar*XtNwidth:                250"),
// const_cast<char*>("PeidaInt*DefMenubar*XtNheight:               30"),
const_cast<char*>("PeidaInt*fontList:           -*-courier-bold-r-normal-*-12-*-*-*-*-*-ISO8859-1"),
const_cast<char*>("PeidaInt*default*fontList:   -*-courier-bold-r-normal-*-12-*-*-*-*-*-ISO8859-1"),
const_cast<char*>("PeidaInt*fontFamilyName:                     *-courier"),    // Pas de blanc apres le nom de font
const_cast<char*>("PeidaInt*courierfontFamilyName:              *-courier"),    //           "        " 
const_cast<char*>("PeidaInt*helveticafontFamilyName:            *-helvetica"),  //           "        " 
const_cast<char*>("PeidaInt*timesfontFamilyName:                *-times"),      //           "        " 
const_cast<char*>("PeidaInt*symbolfontFamilyName:               *-symbol"),     //           "        " 
const_cast<char*>("PeidaInt*XmToggleButton*selectColor:         Red"),
NULL
};


/* --Methode-- */
int PIWdgX::InitXt(int narg, char *arg[])
{
if (top != NULL)  return(0);
// Initialisation ...  
int n;
const char *pc = (const char *)"PIWdgX";
char **ppc;
if (narg > 0)  { n = narg, ppc = arg; }
else { ppc = const_cast<char **>(&pc); n = 1; }
//  strncpy(appname, ppc[0], 63); appname[63] = '\0';
strncpy(appclass,"PeidaInt",63);  appclass[63] = '\0';     
//-----  XtAppInitialize obsolete (X11/R6 , remplace par XtOpenApplication   -  Reza 14/06/99  -----
//  top = XtAppInitialize(&appctx, appclass, NULL, 0, &n, ppc, 
//                      const_cast<String*>(fallback_res), NULL, 0 );
//BUG ? - DEL top = XtVaAppInitialize(&appctx, appclass, NULL, 0, &n, ppc, const_cast<String*>(fallback_res));
top = XtOpenApplication(&appctx, appclass, NULL, 0, &n, ppc, const_cast<String*>(fallback_res), 
                          sessionShellWidgetClass, NULL, 0);
// Reza, Avril 2007 : applicationShell remplace par sessionShell  
//                    doc Lesstif dit que applicationShell est obsolete
//                        applicationShellWidgetClass, NULL, 0);

if (top == NULL) {
  fprintf(stderr, "PIWdgX::InitXt()/ Error XtVaAppInitialize()\n");
  throw PError("PIWdgX::InitXt()/ Error XtVaAppInitialize()");
  }
dpy = XtDisplay(top);
if (dpy == NULL)  {
  fprintf(stderr, "PIWdgX::InitXt()/ Error XtVaAppInitialize()/DisplayConnection\n");
  throw PError("PIWdgX::InitXt()/ Error XtVaAppInitialize()/DisplayConnection");
  }

/*  le GC pour les XCopyArea */
XGCValues  xgv;
xgv.function = GXcopy;
xgv.plane_mask = ~0;
defgc = XCreateGC (dpy, DefaultRootWindow(dpy), GCFunction | GCPlaneMask, &xgv); 

// On va recuperer la fonte par defaut des composantes Motif
XtResource res[] = {
  { (char *)"fontList", (char *)"FontList", XtRString, sizeof(String),
    0, XtRString, const_cast<char *>("-*-courier-bold-*-*-*-*-*-*-*-*-*-*-*") }
};

String fntname;
XtGetApplicationResources(top, &fntname, res, XtNumber(res), NULL, 0);
// scr = XDefaultScreen(dpy);
// printf("-DBG-F= %s \n", fntname);
int count;
char **list;
char buff[256];
strcpy(buff, fntname);
list = XListFonts(dpy, buff, 15, &count);
if (count < 1)  { 
  strcpy(buff,"-*-*-*-*-*-*-12-*-*-*-*-*-*-*" );
  XFreeFontNames(list);
  list = XListFonts(dpy, buff, 15, &count);
  }
if (count < 1)  { 
  strcpy(buff,"-*-*-*-*-*-*-13-*-*-*-*-*-*-*" );
  XFreeFontNames(list);
  list = XListFonts(dpy, buff, 15, &count);
  }
if (count < 1)  { 
  strcpy(buff,"-*-*-*-*-*-*-11-*-*-*-*-*-*-*" );
  XFreeFontNames(list);
  list = XListFonts(dpy, buff, 15, &count);
  }
stdfnt = XLoadQueryFont(dpy, buff);
const char * myfntname = "???";
// Recherche du champ taille en pixel de la fonte : apres le 7eme tiret
int mySzFont = 12;
if (count > 0) {
  myfntname = list[0];
  int kt = 0;
  int kdx = 0;
  char * pcf = list[0];
  //  printf("DBG-X1 : %s \n ", pcf);
  while (kt < 7)  {
    if (pcf[kdx] == '-')  kt++;
    if (pcf[kdx] == '\0')  break;
    kdx++;
    }
  //  printf("DBG-X2 : %s \n ", pcf+kdx);
  int iii = 0;
  while ( (pcf[kdx+iii] != '-') && (pcf[kdx+iii] != '\0') )
     { buff[iii] = pcf[kdx+iii];  iii++; }
  buff[iii] = '\0';
  mySzFont = atoi(buff);
  //  printf("*DBG*X3* %s -> %d \n", buff, mySzFont);
}
// On calcule la taille de la chaine CANCEL (6 caracteres)
char a[2];
XCharStruct  ovr;
int hd, fa, fd, len;  // direction, font-ascent, font-descent len("CANCEL")
XTextExtents(stdfnt, a, 0, &hd, &fa, &fd, &ovr);
len = XTextWidth(stdfnt, "CANCEL", 6);
appSzY = (float)(fa+fd)*1.4+8;  // pour les shadow  $CHECK$ - a ameliorer peut-etre 
appSzX = (float)len*1.4;
appSzFont =  mySzFont ;
// Taille X multiple de 5 pixels, Y mult 2 pixels 
if ( (appSzX % 5) != 0 )   appSzX = 5*(appSzX/5 + 1);
if ( (appSzY % 2) != 0 )   appSzY = 2*(appSzY/2 + 1);
if(appSzY < 10) appSzY = 10;
if(appSzX < 30) appSzX = 30;

// printf("PIWdgX::InitXt(Font=%s- %d %d , %d ) SzX,Y= %d %d - FSz= %d \n", myfntname, fa,fd,len,appSzX, appSzY, appSzFont);
XFreeFontNames(list);
return(0);
}

/* .................................................................*/
/* ................... Gestion de Copier/Coller ....................*/
/* .................................................................*/

// Les Call-Backs Xt

static Boolean forXt_ConvertSelection(Widget w, Atom* sel, Atom *targ, Atom* typ,
                                   XtPointer* value, unsigned long* len, int* format);

static void forXt_LoseSelection(Widget w, Atom* sel);
static void forXt_DoneSelection(Widget w, Atom* sel, Atom *targ);
static void forXt_SelectionValue(Widget w, XtPointer usd, Atom* sel, Atom* typ, 
                                 XtPointer value, unsigned long* len, int* format );

static unsigned int curseltype = PICP_string; // Type de selcetion qu'il peut fournir
static unsigned int reqseltype = PICP_string; // Type de selection demande
static unsigned int provseltype = PICP_string; // Type de selection fourni

/* Nouvelle-Fonction */
Boolean forXt_ConvertSelection(Widget w, Atom* sel, Atom *targ, Atom* typ,
                                   XtPointer* value, unsigned long* len, int* format)
{
if (*targ != XA_STRING)  return(FALSE);
if (!curselwdg)  return(FALSE);
unsigned int ll = 0;
unsigned int styp = reqseltype;
*value = curselwdg->ProvideSelection(styp, ll);
*len=ll;
*typ = XA_STRING;
*format = 8;
provseltype = (styp != 0) ? styp : PICP_string;
return(TRUE);
}

/* Nouvelle-Fonction */
void forXt_LoseSelection(Widget w, Atom* sel)
{
if (curselwdg)  curselwdg->SelectionLost();
curselwdg = NULL; curseltype = PICP_string; 
}

/* Nouvelle-Fonction */
void forXt_DoneSelection(Widget w, Atom* sel, Atom *targ)
{
if (curselwdg)  curselwdg->SelectionTransferEnd();
}

/* Nouvelle-Fonction */
void forXt_SelectionValue(Widget w, XtPointer usd, Atom* sel, Atom* typ, 
                                 XtPointer value, unsigned long* len, int* format )
{
if ( (value != NULL) && (*len > 0) ) 
  ((PIWdgX*)usd)->PasteSelection(provseltype, (void*)value, (*len)) ;
}


// Pour exporter le tableau des pixels du widget en classe  PIPixRGBArray
inline void _col2_fcol_(unsigned long & col, unsigned long & fcol)
{
  if (col > 0x00FFFFFF)  fcol = 0x01000000;
  else if  (col > 0x0000FFFF)  fcol = 0x000010000;
  else if (col > 0x000000FF) fcol = 0x00000100;
  else fcol = 1;  
}   
/* --Methode-- */
void PIWdgX::ExportToRGB(PIPixRGBArray & rgba)
{
Display* mdsp = PIXDisplay();
int scr = XDefaultScreen(mdsp);
int depth = DefaultDepth(mdsp,scr);
Window xw = XtWindow(XtWdg());
unsigned long plane_mask = ~0;  // tous les bits a 1
XImage * ximg = XGetImage(mdsp, xw, 0, 0, XSize(), YSize(), plane_mask, ZPixmap);
//DBG  cout << " Resultat XGetImage -> " << hex << ximg << dec << endl;
if (ximg == NULL)  return;	
                            
unsigned long red,green,blue;
unsigned long fred,fgreen,fblue;
XColor col;
Colormap  cmap = XDefaultColormap (mdsp, scr);
red = 0x000000FF; 
green = 0x0000FF00;
blue = 0x00FF0000;
unsigned short maxrgb = ~0;
col.red = maxrgb;  col.green = col.blue = 0;
if (XAllocColor(mdsp, cmap, &col)) red = col.pixel; 
col.green = maxrgb;  col.red = col.blue = 0;
if (XAllocColor(mdsp, cmap, &col)) green = col.pixel;      
col.blue = maxrgb;  col.red = col.green = 0;
if (XAllocColor(mdsp, cmap, &col)) blue = col.pixel;      
_col2_fcol_(red, fred);
_col2_fcol_(green, fgreen);
_col2_fcol_(blue, fblue);
rgba.SetSize(XSize(), YSize());
unsigned long pixel;
PIPixRGB rgb;
for(int j=0; j<YSize(); j++)
  for(int i=0; i<XSize(); i++) {
    pixel = XGetPixel(ximg, i, j);
    rgb.red = (pixel&red)/fred;
    rgb.green = (pixel&green)/fgreen;
    rgb.blue = (pixel&blue)/fblue;
    rgba(i,j) = rgb;
  }
  XDestroyImage(ximg);
  return;  
}


// Gestion de Copier/Coller
/* --Methode-- */
bool PIWdgX::ClaimSelection(unsigned int typ)
// Pour prendre possession du buffer copier/coller
{
if (XtOwnSelection(XtWdg(), XA_PRIMARY, PIXGetLastEventTime(), forXt_ConvertSelection, 
                   forXt_LoseSelection, forXt_DoneSelection) ) {
#ifdef DEBUG_PIWdgX
  printf("PIWdgX::ClaimSelection(%d) - OK  (Wdg= %lx)\n", typ, (unsigned long)this);
#endif
  curselwdg = this;
  curseltype = (typ != 0) ? typ : PICP_string;
  return (true);
}
else {
#ifdef DEBUG_PIWdgX
  printf("PIWdgX::ClaimSelection() - Probleme (Wdg= %lx)\n", (unsigned long)this);
#endif
  curselwdg = NULL;
  curseltype = PICP_string;
  return (false);
}
}

/* --Methode-- */
void PIWdgX::SelectionLost()
// Appele quand le PIWdg perd la possession du buffer copier/coller
{
return;
}

/* --Methode-- */
unsigned int PIWdgX::RequestSelection(unsigned int typ)
{
// Pour demander le contenu du buffer de copier/coller
#ifdef DEBUG_PIWdgX
printf("PIWdgX::RequestSelection(%d) (Wdg= %lx - %lx) \n", typ,  
        (unsigned long)this, (unsigned long)curselwdg);
#endif
reqseltype = (typ != 0) ? typ : PICP_string;
XtGetSelectionValue(XtWdg(), XA_PRIMARY, XA_STRING, forXt_SelectionValue, 
                    (XtPointer)this, PIXGetLastEventTime());
return(reqseltype);
}

static char* rs = NULL;

/* --Methode-- */
void* PIWdgX::ProvideSelection(unsigned int& typ, unsigned int& len)
// Le widget doit fournier une l zone memoire contenant la selection
// en un type donne
// Renvoie le pointeur de cette zone, sa taille et son typ
{
rs = new char[128];
sprintf(rs, "Test-of-PIWdgX::ProvideSelection(%d)- %lx", typ,(long)rs);
len = strlen(rs);
return(rs);
}

/* --Methode-- */
void PIWdgX::SelectionTransferEnd()
{
delete[] rs;
}


/* --Methode-- */
void PIWdgX::PasteSelection(unsigned int typ, void *buff, unsigned int l)
{
// Methode appele apres que le widget ait fait RequestSelection
// Le typ de donnees fourni ainsi que les donnees et leur taille 
// sont en argument 
#ifdef DEBUG_PIWdgX
char* mbuff = new char[l+1];
strncpy(mbuff, (char *)buff, l);
mbuff[l] = '\0';
printf("PIWdgX::PasteSelection(%d, %lx, %d) [%s] \n", typ, (long)buff, l, mbuff);
delete[] mbuff;
#endif
return;
}

//  Copie depuis un PIWdgGen
void PIWdgX::CopyFrom(PIWdgGen* wdg, int ox, int oy, int dx, int dy, int x, int y)
{
PIWdgX* wx = (PIWdgX*)wdg;
XCopyArea(XtDisplay(XtWdg()), XtWindow(wx->XtWdg()), XtWindow(XtWdg()), defgc, ox, oy, 
          (unsigned int)dx, (unsigned int)dy, x, y);
}


// Declaration de l' EventHandler Xt
static void evthandler_piwdgx (Widget wdgp, XtPointer, XEvent* evt, Boolean* cont);


/* --Methode-- */
void PIWdgX::AddDrawHandler(PIEventHandler* drwh, bool ad)
{
PIWdgGen::AddDrawHandler(drwh, ad);
if (mDHlist.size() == 1)
  XtInsertEventHandler( XtWdg(), ExposureMask, FALSE, evthandler_piwdgx, this, XtListTail);
}

/* --Methode-- */
void PIWdgX::RemoveDrawHandler(PIEventHandler* drwh)
{
PIWdgGen::RemoveDrawHandler(drwh);
if (mDHlist.size() == 0) XtRemoveEventHandler( XtWdg(), ExposureMask, FALSE, evthandler_piwdgx, this);
}

/* --Methode-- */
void PIWdgX::AddEventHandler(PIEventHandler* evh, unsigned long evtmask, bool ad)
{
PIWdgGen::AddEventHandler(evh, evtmask, ad);
EventMask mask = 0;
// if (evtmask & PIEvent_Resize)  pas traite pour le moment
if (evtmask & PIEvent_Enter)  mask |= EnterNotify;
if (evtmask & PIEvent_Leave)  mask |= LeaveNotify;
if (evtmask & PIEvent_But1Press)  mask |= ButtonPressMask;
if (evtmask & PIEvent_But1Release)  mask |= ButtonReleaseMask;
if (evtmask & PIEvent_But2Press)  mask |= ButtonPressMask;
if (evtmask & PIEvent_But2Release)  mask |= ButtonReleaseMask;
if (evtmask & PIEvent_But3Press)  mask |= ButtonPressMask;
if (evtmask & PIEvent_But3Release)  mask |= ButtonReleaseMask;
if (evtmask & PIEvent_PtrMove)  mask |= PointerMotionHintMask;
if (evtmask & PIEvent_Ptr1Move)  mask |= (PointerMotionHintMask | Button1MotionMask);
if (evtmask & PIEvent_Ptr2Move)  mask |= (PointerMotionHintMask | Button2MotionMask);
if (evtmask & PIEvent_Ptr3Move)  mask |= (PointerMotionHintMask | Button3MotionMask);
if (evtmask & PIEvent_Keyboard)  mask |= KeyPressMask;
// printf("PIWdgX::AddEventHandler() Mask = %lx \n", (long)mask);
XtInsertEventHandler( XtWdg(), mask, FALSE, evthandler_piwdgx, this, XtListTail);
}

/* --Methode-- */
void PIWdgX::RemoveEventHandler(PIEventHandler* evh)
{
PIWdgGen::RemoveEventHandler(evh);
//cout << "DBG-PIWdgX::RemoveEventHandler( " << hex << evh << dec << ") mEHlist.size()="
//      << mEHlist.size() << endl;
if (mEHlist.size() > 0) return; 
EventMask mask = EnterNotify;
mask |= LeaveNotify;
mask |= ButtonPressMask;
mask |= ButtonRelease;
mask |= ButtonPressMask;
mask |= ButtonRelease;
mask |= ButtonPressMask;
mask |= ButtonRelease;
mask |= PointerMotionHintMask;
mask |= (PointerMotionHintMask | Button1MotionMask);
mask |= (PointerMotionHintMask | Button2MotionMask);
mask |= (PointerMotionHintMask | Button3MotionMask);
mask |= KeyPressMask;
XtRemoveEventHandler( XtWdg(), mask, FALSE, evthandler_piwdgx, this);
}

/* --Methode-- */
void PIWdgX::CallDrawHandlers(int x0, int y0, int dx, int dy)
{
PIGraphicWin* g = new PIGraphicWin(this);
PIEventHandler* eh;
list<EvHand>::iterator it;
for(it= mDHlist.begin(); it != mDHlist.end(); it++) { 
  eh = (*it).evh;
  eh->SetCurrentWdg(this);
  eh->SetEventInfo(PIEvent_Draw, x0, y0, 0, PIKM_Blank, 0);
  g->SaveGraphicAtt();
  eh->Draw(g, x0, y0, dx, dy);
  g->RestoreGraphicAtt();
  }
delete g;
}

/* --Methode-- */
void PIWdgX::CallEventHandlers(unsigned long evt, int px, int py,
                               int k, int km, unsigned long tm)
{
//cout << "DBG-PIWdgX:CallEventHandlers() - mEHlist.size()=" << mEHlist.size() << endl;
PIEventHandler* eh;
list<EvHand>::iterator it;
// On fait d'abord une copie pour eviter les problemes
// lies a l'ajout ou la supression d'event-handler par un ProcessEvent()
list<EvHand> cEHlist;
for(it= mEHlist.begin(); it != mEHlist.end(); it++) { 
  if (!((*it).mask & evt))  continue; 
  cEHlist.push_back(*it);
}
// Et on refait la boucle sur la liste copiee ...
for(it= cEHlist.begin(); it != cEHlist.end(); it++) { 
  eh = (*it).evh;
  eh->SetCurrentWdg(this);
  eh->SetEventInfo((PIEventMask)evt, px, py, k, (PIKeyModifier)km, tm);
  eh->ProcessEvent();
  }
}


// -------   Event Handler Xt ----------
/* Nouvelle-Fonction */
void evthandler_piwdgx (Widget wdgp, XtPointer usd, 
                             XEvent* evt, Boolean* cont)
{

*cont = true ; 
PIWdgX* wx = (PIWdgX*)usd;
PIEventMask evm = PIEvent_None;
PIKeyModifier kmod = PIKM_Blank;

switch (evt->type) {
  case Expose :
    wx->CallDrawHandlers(evt->xexpose.x , evt->xexpose.y , evt->xexpose.width , evt->xexpose.height);
    break;
  case EnterNotify : 
    wx->CallEventHandlers(PIEvent_Enter, evt->xcrossing.x, evt->xcrossing.y, 0, 
                          PIKM_Blank, evt->xcrossing.time);
    PIXSetLastEventTimeSerial(evt->xcrossing.time, evt->xcrossing.serial);
    break;

  case LeaveNotify : 
    wx->CallEventHandlers(PIEvent_Leave, evt->xcrossing.x, evt->xcrossing.y, 0, 
                          PIKM_Blank, evt->xcrossing.time);
    PIXSetLastEventTimeSerial(evt->xcrossing.time, evt->xcrossing.serial);
  break;

  case ButtonPress :
    if  (evt->xbutton.state & ShiftMask)   
      kmod = (PIKeyModifier) (kmod | PIKM_Shift);
    if  (evt->xbutton.state & ControlMask) 
      kmod = (PIKeyModifier) (kmod | PIKM_Cntl);
    if  (evt->xbutton.state & Mod1Mask)    
      kmod = (PIKeyModifier) (kmod | PIKM_Alt);
    if (evt->xbutton.button == 1) evm = PIEvent_But1Press;
    else if (evt->xbutton.button == 2) evm = PIEvent_But2Press;
    else if (evt->xbutton.button == 3) evm = PIEvent_But3Press;
    wx->CallEventHandlers(evm, evt->xbutton.x, evt->xbutton.y, 0, 
                          kmod, evt->xbutton.time);
    PIXSetLastEventTimeSerial(evt->xbutton.time, evt->xbutton.serial);
  break;

  case ButtonRelease :
    if  (evt->xbutton.state & ShiftMask)   
      kmod = (PIKeyModifier) (kmod | PIKM_Shift);
    if  (evt->xbutton.state & ControlMask) 
      kmod = (PIKeyModifier) (kmod | PIKM_Cntl);
    if  (evt->xbutton.state & Mod1Mask)    
      kmod = (PIKeyModifier) (kmod | PIKM_Alt);
    if (evt->xbutton.button == 1) evm = PIEvent_But1Release;
    else if (evt->xbutton.button == 2) evm = PIEvent_But2Release;
    else if (evt->xbutton.button == 3) evm = PIEvent_But3Release;

    wx->CallEventHandlers(evm, evt->xbutton.x, evt->xbutton.y, 0, 
                          kmod, evt->xbutton.time);
    PIXSetLastEventTimeSerial(evt->xbutton.time, evt->xbutton.serial);
  break;

  case MotionNotify :
    {
    int xw, yw, xr, yr;
    unsigned int key_but;
    Window rw, cw;
    if ( evt->xmotion.is_hint == NotifyHint ) { 
      if (!XQueryPointer( XtDisplay(wdgp), evt->xmotion.window, &rw, &cw,
                  &xr, &yr, &xw, &yw, &key_but) ) break ;
      }
    else { key_but =  evt->xmotion.state ; xw = evt->xmotion.x;  yw = evt->xmotion.y; }
    if  (key_but & Button1Mask ) evm = PIEvent_Ptr1Move;
    else  if (key_but & Button2Mask ) evm = PIEvent_Ptr2Move;
    else  if (key_but & Button3Mask ) evm = PIEvent_Ptr3Move;
    else if ( !(key_but & (Button4Mask|Button5Mask)) )  evm = PIEvent_PtrMove;

    if  (key_but & ShiftMask)   kmod = (PIKeyModifier) (kmod | PIKM_Shift);
    if  (key_but & ControlMask) kmod = (PIKeyModifier) (kmod | PIKM_Cntl);
    if  (key_but & Mod1Mask)    kmod = (PIKeyModifier) (kmod | PIKM_Alt);

    wx->CallEventHandlers(evm, xw, yw, 0, kmod, evt->xbutton.time);
    PIXSetLastEventTimeSerial(evt->xmotion.time, evt->xmotion.serial);    
    }
  break;

  case KeyPress :
    {
    XComposeStatus cs;
    KeySym key;
    char buf[10];
    int i,nc,rkey;

  
    kmod = PIKM_Blank;
    nc = XLookupString(&(evt->xkey), buf, 10, &key, &cs);

    if  (evt->xkey.state & ShiftMask)   
      kmod = (PIKeyModifier) (kmod | PIKM_Shift);
    if  (evt->xkey.state & ControlMask) 
      kmod = (PIKeyModifier) (kmod | PIKM_Cntl);
    if  (evt->xkey.state & Mod1Mask)    
      kmod = (PIKeyModifier) (kmod | PIKM_Alt);
    switch (key) {
      case XK_Return :
        rkey = PIK_Return;
      break;
      case XK_KP_Enter :
        rkey = PIK_Enter;
      break;
      case XK_Up :
        rkey = PIK_Up;
      break;
      case XK_Down :
        rkey = PIK_Down;
      break;
      case XK_Left :
        rkey = PIK_Left;
      break;
      case XK_Right :
        rkey = PIK_Right;
      break;
      case XK_Prior :
        rkey = PIK_Previous;
      break;
      case XK_Next :
        rkey = PIK_Next;
      break;
      default :
        rkey = 0;
      break;
    }
    if (rkey > 0)  wx->CallEventHandlers(PIEvent_Keyboard, evt->xkey.y, evt->xkey.x, 
                                         rkey, kmod, evt->xkey.time);
    else for(i=0; i<nc; i++)  
            wx->CallEventHandlers(PIEvent_Keyboard, evt->xkey.y, evt->xkey.x, 
                                 (int)(buf[i]), kmod, evt->xkey.time);
    PIXSetLastEventTimeSerial(evt->xkey.time, evt->xkey.serial);    

  }
  break;
}

return;
}


// -------- La classe PIScreenBuffer ----------
/* --Methode-- */
PIScreenBuffer::PIScreenBuffer(int sx, int sy)
{
if (sx < 1) sx = 1;
if (sy < 1) sy = 1;
mSx = sx;  mSy = sy;
Display * dsx = PIXDisplay();
Window rw = DefaultRootWindow(dsx);
xScrbuff = XCreatePixmap(dsx, rw, sx, sy, DefaultDepth(dsx, DefaultScreen(dsx)) );
}
/* --Methode-- */
PIScreenBuffer::~PIScreenBuffer()
{
XFreePixmap(PIXDisplay(),xScrbuff); 
}

/* --Methode-- */
int PIScreenBuffer::XSize()
{
return(mSx);
}

/* --Methode-- */
int PIScreenBuffer::YSize()
{
return(mSx);
}

/* --Methode-- */
void PIScreenBuffer::CopyFromWdg(PIWdg* wdg, int ox, int oy, int dx, int dy, int x, int y)
{
XCopyArea(XtDisplay(wdg->XtWdg()), XtWindow(wdg->XtWdg()), XScrBuffer(), defgc, ox, oy, 
          (unsigned int)dx, (unsigned int)dy, x, y);
}

/* --Methode-- */
void PIScreenBuffer::CopyToWdg(PIWdg* wdg, int ox, int oy, int dx, int dy, int x, int y)
{
XCopyArea(XtDisplay(wdg->XtWdg()), XScrBuffer(), XtWindow(wdg->XtWdg()), defgc, ox, oy, 
          (unsigned int)dx, (unsigned int)dy, x, y);
}

/* --Methode-- */
void PIScreenBuffer::CopyFrom(PIScreenBuffer* grb, int ox, int oy, int dx, int dy, int x, int y)
{

XCopyArea(PIXDisplay(), grb->XScrBuffer(), XScrBuffer(), defgc, ox, oy, 
          (unsigned int)dx, (unsigned int)dy, x, y);
}
