#include "sopnamsp.h"
#include "machdefs.h"
#include <stdlib.h>
#include <stdio.h>

#include <X11/Intrinsic.h>
#include <X11/StringDefs.h>

#include <X11/IntrinsicP.h>
#include <X11/CoreP.h>

#include <X11/keysym.h>

#include "pixtbaseP.h"
#include "pixtbase.h"

// #define DEBUG_PIXTB

 
//  ------- Pb de gestion du focus-keyboard  Motif-PIBaseWdg -------
// ** Note 30/04/98  Reza
// Il y un probleme d'attribution du focus-keyboard entre Widget Motif et
// PIBaseWdg (Widget PIXtBase) les Attributs XmNnavigationType et XmNtraversalOn
// ont ete desactives pour les StdWdgX - Le probleme n'a pas pu etre resolu
// meme en attribuant les attributs  XmNnavigationType XmNtraversalOn 
// (et XmNsensitive) a PIXtBase, ni en utilisant 
// XSetInputFocus(XtDisplay (wdgp), XtWindow(wdgp), RevertToParent, evt->xbutton.time)
// Solution pour le moment :
//  XmNnavigationType =XmNONE et XmNtraversalOn=FALSE pour les PIStdWdgX 
// sauf pour PIText ou XmNtraversalOn=TRUE


/*  Construction du widget Xt PIXtBase   */

static void     init_class_pixtbase(void);

static void     init_pixtbase    (Widget, Widget, ArgList, Cardinal*);
static void     destroy_pixtbase (Widget);
static void     resize_pixtbase  (Widget);
static void     expose_pixtbase  (Widget, XEvent*, Region);


// Si on ne veut pas utiliser XtInheritAcceptFocus
// static Boolean  acceptfocus_pixtbase   (Widget, Time* ); 


static XtResource resources[] ={
  {const_cast<char*>(PIXNobject) ,const_cast<char*>("Object"), XtRPointer, sizeof(XtRPointer),
   XtOffset(PIXtBaseWidget,  pixtbase.objet), XtRImmediate, (XtPointer)0},
};


PIXtBaseClassRec  piXtBaseClassRec = {
/* Core Class Part */
{

(WidgetClass) &coreClassRec,    /* pointer to superclass ClassRec   */
(char*)"PIXtBase",         	/* widget resource class name       */
sizeof(PIXtBaseRec),	        /* size in bytes of widget record   */
init_class_pixtbase,            /* class_initialize                 */
NULL, 			        /* dynamic initialization           */
FALSE,       		        /* has class been initialized?      */
init_pixtbase,                  /* initialize                       */
NULL,			        /* notify that initialize called    */
XtInheritRealize,               /* XCreateWindow for widget         */
// actions,     		/* widget semantics name to proc map*/
// XtNumber(actions),           /* number of entries in actions     */
NULL,                           /* widget semantics name to proc map*/
0,                              /* number of entries in actions     */
resources,                      /* resources             */
XtNumber(resources),            /* resources             */
NULLQUARK,		        /* resource class quarkified        */
TRUE,			        /* compress MotionNotify for widget */
TRUE,			        /* compress Expose events for widget*/
TRUE,			        /* compress enter and leave events  */
TRUE,			        /* select for VisibilityNotify      */
destroy_pixtbase,	        /* free data for subclass pointers  */
resize_pixtbase,                /* geom manager changed widget size */
expose_pixtbase,       	        /* rediplay window                  */
NULL,		                /* set subclass resource values     */
NULL,			        /* notify that set_values called    */
XtInheritSetValuesAlmost,       /* set_values got "Almost" geo reply*/
NULL,		                /* notify that get_values called    */
XtInheritAcceptFocus,           /* assign input focus to widget     */
// acceptfocus_pixtbase,           /* assign input focus to widget     */
XtVersion,	                /* version of intrinsics used       */
NULL,		                /* list of callback offsets         */
// translations,	        /* state machine                    */
NULL,                           /* state machine                    */
XtInheritQueryGeometry,         /* return preferred geometry        */
XtInheritDisplayAccelerator,    /* display your accelerator         */
NULL		                /* pointer to extension record      */
}
/* PIXtBase */
,{   NULL }

};

WidgetClass piXtBaseWidgetClass = (WidgetClass) &piXtBaseClassRec;


/*  Last XEvent Serial Number and Time-Stamp , and Key-state */
static Time last_time_xevt = 0;
static unsigned long last_serial_xevt = 0;
static unsigned int  last_state_xevt = 0;


Time PIXGetLastEventTime() { return(last_time_xevt); }
unsigned long PIXGetLastEventSerial() { return(last_serial_xevt); }
void PIXSetLastEventTimeSerial(Time t, unsigned long ser) 
{ last_time_xevt = t;  last_serial_xevt = ser; }
void PIXGetLastEventInfo(unsigned int& st, Time& t)
{ st = last_state_xevt;  t = last_time_xevt; }

/* Gestion de variable d'environnement pour choix Mod1Mask ou Mod2Mask */
static bool fgenv_kb_modmasks = false;
static int  sel_kb_modmasks = 3;  // Nov 2007: On passe le defaut a 3, au lieu de 1

/* Nouvelle-Fonction */
static void init_class_pixtbase()
{
// Pour le choix Mod1Mask OU Mod2mask OU ( Mod1Mask | Mod2mask )
// Il faut en particulier Mod2Mask sur serveur X11/MacOSX (touche pomme)
//                      Reza / Septembre 2003
// Var. Env  PIXKBMODMASK   =2 -> Mod2Mask
//                          =3 -> Mod1Mask | Mod2Mask
//                          =0 -> Pas de ModMask
//                          =autre -> Mod1Mask (defaut) 
if ( !fgenv_kb_modmasks ) {
  char *envmodmask = getenv("PIXKBMODMASK");
  if (envmodmask) {
    if (envmodmask[0] == '0')  sel_kb_modmasks = 0;
    else if (envmodmask[0] == '1')  sel_kb_modmasks = 1;
    else if (envmodmask[0] == '2')  sel_kb_modmasks = 2;
    else if (envmodmask[0] == '3')  sel_kb_modmasks = 3;
    else sel_kb_modmasks = 1;
  }
}
#ifdef DEBUG_PIXTB
puts("Debug_init_class_pixtbase() ");
#endif
return;
}

// Pour traiter les etats de changements de visibilite de la fenetre
/* Nouvelle-Fonction */
void visibchange_handler_pixtbase (Widget wdgp, XtPointer /*closure*/, 
                             XEvent* evt, Boolean* cont)
{
#ifdef DEBUG_PIXTB
printf("Debug_visibchange_handler_pixtbase: Wdg= %lx Object= %lx  fgvis_expose= %d (EvtType=%d VisSt=%d)\n", 
  (long)wdgp, (long)(((PIXtBaseWidget)wdgp)->pixtbase.objet),
  ((PIXtBaseWidget)wdgp)->pixtbase.vis_expose_fg, (int)evt->type,(int)evt->xvisibility.state);
#endif
PIXtBaseWidget bwdg = (PIXtBaseWidget)wdgp;
if (bwdg->pixtbase.vis_expose_fg != 1) return;
if (evt->xvisibility.state == VisibilityFullyObscured)  return;
int x0, y0, dx, dy;
x0 = y0 = 0;
dx = wdgp->core.width;  dy = wdgp->core.height;
(bwdg->pixtbase.objet)->eXposeProcess(x0, y0, dx, dy);
bwdg->pixtbase.vis_expose_fg = 0;
}

/* Nouvelle-Fonction */
static void init_pixtbase (Widget request, Widget wdg,
                          ArgList /*args*/, Cardinal* /*narg*/)
{
PIXtBaseWidget wdgp;
wdgp = (PIXtBaseWidget)wdg;

if(request->core.width<=0)  wdgp->core.width  = 10;
if(request->core.height<=0) wdgp->core.height = 10;
// get_GCs (wdgp);
#ifdef DEBUG_PIXTB
printf("Debug_init_pixtbase: Wdg=%lx Object= %lx  \n", 
(long)wdgp, (long)(wdgp->pixtbase.objet));
#endif

// Pour gerer les exposes event avec fenetre non visible ...
wdgp->pixtbase.vis_expose_fg = 0;
XtAddEventHandler(wdg, VisibilityChangeMask, FALSE, visibchange_handler_pixtbase, NULL);
return;
}

/* Nouvelle-Fonction */
static void destroy_pixtbase (Widget wdgp)
{
#ifdef DEBUG_PIXTB
printf("Debug_destroy_pixtbase: Wdg= %lx Object= %lx \n", (long)wdgp, 
(long)(((PIXtBaseWidget)wdgp)->pixtbase.objet) );
#endif
// free_GCs((PIXtBaseWidget)wdgp);
//    $CHECK$ Reza  21/11/97
// J'ai l'impression que cette fonction n'est pas appellee au moment 
// de destruction du Widget - Par contre la fonction leave est appelee
// si l'action correspondante a ete enregistree ?!
}


/* Nouvelle-Fonction */
static void resize_pixtbase (Widget wdgp)
{
#ifdef DEBUG_PIXTB
printf("Debug_resize_pixtbase: Wdg=%lx Object= %lx \n", (long)wdgp, 
(long)(((PIXtBaseWidget)wdgp)->pixtbase.objet) );
#endif
if (((PIXtBaseWidget)wdgp)->pixtbase.objet) 
  (((PIXtBaseWidget)wdgp)->pixtbase.objet)->Resize();
return;
}

/* Nouvelle-Fonction */
static void expose_pixtbase (Widget  wdgp, XEvent* /*event*/, Region region)
{
#ifdef DEBUG_PIXTB
printf("Debug_expose_pixtbase: Wdg=%lx Object= %lx \n", (long)wdgp, 
(long)(((PIXtBaseWidget)wdgp)->pixtbase.objet) );
#endif
if (!(wdgp->core.visible))  { 
  ((PIXtBaseWidget)wdgp)->pixtbase.vis_expose_fg = 1;
  return;
}
if ( ((PIXtBaseWidget)wdgp)->pixtbase.objet ) {
  XRectangle  xrec;
  int x0, y0, dx, dy;
  if (region) {
    XClipBox(region, &xrec);
    x0 = xrec.x;  y0 = xrec.y;
    dx = xrec.width;  dy = xrec.height;
  }
  else {
    x0 = y0 = 0;
    dx = wdgp->core.width;  dy = wdgp->core.height;
  }
  (((PIXtBaseWidget)wdgp)->pixtbase.objet)->eXposeProcess(x0, y0, dx, dy);
  ((PIXtBaseWidget)wdgp)->pixtbase.vis_expose_fg = 0;
}
return;
}

/* Nouvelle-Fonction 
static Boolean  acceptfocus_pixtbase   (Widget wdgp , Time* )
{
// printf("acceptfocus_pixtbase() %lx %x \n",  ((PIXtBaseWidget)wdgp)->pixtbase.myeventmask, ShiftMask );
if (  ((PIXtBaseWidget)wdgp)->pixtbase.myeventmask & ShiftMask  )  return TRUE;
else return FALSE;
}
*/

/* -------- Fonction de traitement des evenements --------- */
/* Nouvelle-Fonction */
void event_handler_pixtbase (Widget wdgp, XtPointer /*closure*/, 
                             XEvent* evt, Boolean* cont)
{

*cont = true ; 
switch (evt->type) {
  case EnterNotify : 
#ifdef DEBUG_PIXTB
    printf("Debug_enter_pixtbase: Wdg=%lx Object= %lx \n", (long)wdgp, 
           (long)(((PIXtBaseWidget)wdgp)->pixtbase.objet) );
#endif
    last_time_xevt = evt->xcrossing.time;
    last_serial_xevt = evt->xcrossing.serial;
    last_state_xevt = evt->xcrossing.state;
//    if (((PIXtBaseWidget)wdgp)->pixtbase.objet) 
    (((PIXtBaseWidget)wdgp)->pixtbase.objet)->Enter();
  break;

  case LeaveNotify : 
#ifdef DEBUG_PIXTB
    printf("Debug_leave_pixtbase: Wdg=%lx Object= %lx \n", (long)wdgp, 
           (long)(((PIXtBaseWidget)wdgp)->pixtbase.objet) );
#endif
    last_time_xevt = evt->xcrossing.time;
    last_serial_xevt = evt->xcrossing.serial;
    last_state_xevt = evt->xcrossing.state;
//    if (((PIXtBaseWidget)wdgp)->pixtbase.objet) 
       (((PIXtBaseWidget)wdgp)->pixtbase.objet)->Leave();
  break;

  case ButtonPress :
    last_time_xevt = evt->xbutton.time;
    last_serial_xevt = evt->xbutton.serial;
    last_state_xevt = evt->xbutton.state;
    if ( (evt->xbutton.button == 1) && ( ((PIXtBaseWidget)wdgp)->pixtbase.myeventmask & Button1Mask) )
      (((PIXtBaseWidget)wdgp)->pixtbase.objet)->But1Press(evt->xbutton.x, evt->xbutton.y);
    else  if ( (evt->xbutton.button == 2) && ( ((PIXtBaseWidget)wdgp)->pixtbase.myeventmask & Button2Mask) )
      (((PIXtBaseWidget)wdgp)->pixtbase.objet)->But2Press(evt->xbutton.x, evt->xbutton.y);
    else  if ( (evt->xbutton.button == 3)  && ( ((PIXtBaseWidget)wdgp)->pixtbase.myeventmask & Button3Mask) )
      (((PIXtBaseWidget)wdgp)->pixtbase.objet)->But3Press(evt->xbutton.x, evt->xbutton.y);
  break;

  case ButtonRelease :
    last_time_xevt = evt->xbutton.time;
    last_serial_xevt = evt->xbutton.serial;
    last_state_xevt = evt->xbutton.state;
    if ( (evt->xbutton.button == 1) && ( ((PIXtBaseWidget)wdgp)->pixtbase.myeventmask & Button1Mask) )
      (((PIXtBaseWidget)wdgp)->pixtbase.objet)->But1Release(evt->xbutton.x, evt->xbutton.y);
    else  if ( (evt->xbutton.button == 2) && ( ((PIXtBaseWidget)wdgp)->pixtbase.myeventmask & Button2Mask) )
      (((PIXtBaseWidget)wdgp)->pixtbase.objet)->But2Release(evt->xbutton.x, evt->xbutton.y);
    else  if ( (evt->xbutton.button == 3)  && ( ((PIXtBaseWidget)wdgp)->pixtbase.myeventmask & Button3Mask) )
      (((PIXtBaseWidget)wdgp)->pixtbase.objet)->But3Release(evt->xbutton.x, evt->xbutton.y);
  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 | Button2Mask | Button3Mask ) ) ) break;
      last_time_xevt = evt->xmotion.time;
      last_serial_xevt = evt->xmotion.serial;
      last_state_xevt = evt->xmotion.state;
      if  (key_but & Button1Mask ) 
        (((PIXtBaseWidget)wdgp)->pixtbase.objet)->Ptr1Move(xw, yw);
      else  if (key_but & Button2Mask ) 
        (((PIXtBaseWidget)wdgp)->pixtbase.objet)->Ptr2Move(xw, yw);
      else  if (key_but & Button3Mask ) 
        (((PIXtBaseWidget)wdgp)->pixtbase.objet)->Ptr3Move(xw, yw);
      else if ( !(key_but & (Button4Mask|Button5Mask)) ) 
        (((PIXtBaseWidget)wdgp)->pixtbase.objet)->PtrMove(xw, yw);
    }
  break;

  case KeyPress :
    {
    XComposeStatus cs;
    KeySym key;
    char buf[10];
    int i,nc,rkey;
    PIKeyModifier kmod;
  
    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);
    // Choix Mod1Mask Et/Ou Mod2Mask par variable sel_kb_modmasks
    //                      Reza / Septembre 2003
    if ((sel_kb_modmasks == 1) && (evt->xkey.state & Mod1Mask) )
      kmod = (PIKeyModifier) (kmod | PIKM_Alt);
    if ((sel_kb_modmasks == 2) && (evt->xkey.state & Mod2Mask) )
      kmod = (PIKeyModifier) (kmod | PIKM_Alt);
    if ((sel_kb_modmasks == 3) && 
	((evt->xkey.state & Mod1Mask) || (evt->xkey.state & Mod2Mask)) )
      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)  (((PIXtBaseWidget)wdgp)->pixtbase.objet)->Keyboard(rkey, kmod);
    else for(i=0; i<nc; i++)  
      (((PIXtBaseWidget)wdgp)->pixtbase.objet)->Keyboard((int)(buf[i]), kmod);
  }
  break;
}

return;
}


