#include<stdio.h>
#include<signal.h>
#include<sys/types.h>
#include<X11/Intrinsic.h>
#include<X11/StringDefs.h>

typedef struct{
  Boolean fixedVolume;
  Boolean playWhenSilent;
} AppData;

static AppData app_data;

static XtResource Resources[] = {
  {
    "fixedVolume","FixedVolume",XtRBoolean,sizeof(Boolean),
      XtOffsetOf( AppData,fixedVolume ),
      XtRImmediate,(XtPointer)FALSE ,
  },
  {
    "playWhenSilent","PlayWhenSilent",XtRBoolean,sizeof(Boolean),
    XtOffsetOf( AppData,playWhenSilent ),
    XtRImmediate,(XtPointer)FALSE,
  },
};


static XrmOptionDescRec Options[] = {
  {"-fixed","*fixedVolume",XrmoptionNoArg,"TRUE" },
  {"+fixed","*fixedVolume",XrmoptionNoArg,"FALSE" },
  {"-force","*playWhenSilent",XrmoptionNoArg,"TRUE" },
  {"+force","*playWhenSilent",XrmoptionNoArg,"FALSE" },
};


/* prototypes */

int play( void );
void nextline( void );

/* 変数 */

int ErrLin = 1;
int ErrCol = 0;

int FixedVol; /* ボリューム制御しない? */

FILE* Fp;
Display *Disp;

static XKeyboardState State; /* キーボードコントロールの保存 */

static XtAppContext App;   /* アプリケーションコンテクスト */

/* ウィジット（クラス) */

static Widget
       Top;              /* 最上位                        */


static void timi( XtPointer c, XtIntervalId id );

static void init( void )
{
  XKeyboardState v;

  XGetKeyboardControl( Disp,&State );

  if( FixedVol ){
    if( app_data.playWhenSilent || State.bell_percent != 0 ){
      v.bell_percent = -1;
      XChangeKeyboardControl( Disp,KBBellPercent,&v );
    }
  }
}


static recover_state( void )
{
  unsigned long mask;

  mask = KBBellPitch | KBBellDuration;
  if( FixedVol )
    mask |= KBBellPercent;

  XChangeKeyboardControl( Disp,mask,&State );
  XFlush( Disp );
}


/* シグナルハンドラ */

static void sighandler( void )
{
  recover_state();
  exit(0);
}


static void timi( XtPointer c,XtIntervalId id )
{
  int l;

  for(;;){
    l = play();

    if( l == 0 ){
      recover_state();
      exit(0);
    }

    if( l == -1 ){
      fprintf(stderr,"Error in Line %d  Column %d\n",ErrLin,ErrCol );
      nextline();
    }else{
      XtAppAddTimeOut( App, l,(XtTimerCallbackProc)timi,NULL );
      return;
    }
  }
}


int main(int argc,char **argv)
{
  XtSetLanguageProc(NULL,NULL,NULL);

  Top = XtVaAppInitialize(&App,"XPlayBeep",Options,XtNumber(Options),
			&argc,argv,NULL,NULL);

  XtVaGetApplicationResources( Top,
			      &app_data,
			      Resources,
			      XtNumber( Resources ) );

  FixedVol = app_data.fixedVolume;

  if( argc < 2 )
    Fp = stdin;
  else if( ( Fp = fopen( argv[1],"r" ) ) == NULL ){
    fprintf(stderr,"can't open file: %s\n",argv[1] );
    exit(1);
  }

  Disp = XtDisplay( Top );

  init();

  signal( SIGTERM,sighandler );
  signal( SIGINT,sighandler );

  XtAppAddTimeOut( App, 0,(XtTimerCallbackProc)timi,NULL );
  XtAppMainLoop(App);

  return 0;
}
