/************************************************************************/
/* Module : db.c						        */
/* Purpose: database module				                */
/* By     : Keith R. Davis					        */
/* Date   : 12/11/95					                */
/* Notes  : Copyright(c) 1996 Whit River Software			*/
/*          Copyright(c) 1994, Regents of the University of California  */
/************************************************************************/

#include <Xm/Xm.h>			/* motif lib header		*/
#include <Xm/CutPaste.h>                /* motif clipboard header       */
#include <Xm/Text.h>	          	/* text widget header		*/
#include <X11/cursorfont.h>             /* X cursors                    */
#ifndef AMIGA
#include <sys/signal.h> 
#else
#include <sys/tcp_types.h>
#include <signal.h>
#endif
#include <string.h>			/* string header		*/
#include <stdio.h>                      /* stdio header                 */
#include <pwd.h>                        /* passwd header                */

#include "mquel.h"                      /* mquel module header          */
#include "llist.h"                      /* linked list header           */
#include "db.h"				/* db data header		*/
#include "util.h"                       /* utility function header      */

/* databse globals , this needs to be eliminated !! */	
	
PGconn *db = NULL;		        /* db ptr		        */
char dbname[DB_NAME_SZ];		/* db name 	         	*/
char host[HOST_NAME_SZ];      	        /* host name 	                */
char port[PORT_NAME_SZ];		/* port 		        */
char spool_file[MAX_PATH_LEN];          /* spool file                   */         
char printer[PRINT_NAME_SZ];            /* printer                      */
int col_width;                          /* default column width         */ 
int connected = 0;                      /* connect flag                 */

/************************************************************************/
/* Function: DB_Connect                                                 */
/* Purpose : establishes connection to postgres database                */
/* Params  :                                                            */
/* Returns : 1 on SUCCESS / 0 on FAILURE                                */
/* Notes   :                                                            */
/************************************************************************/

int DB_Connect(void)
{
  char db_msg[ERR_MSG_SIZE];

  DB_Grab();

  if(connected)
    PQfinish(db);

  db = PQsetdb(host, port, NULL, NULL, dbname);

  if (PQstatus(db) == CONNECTION_BAD) {

    sprintf(db_msg,"Connection to database '%s' failed.\nERROR: %s", 
	    dbname, PQerrorMessage(db));
    ErrorMsg("Connect", db_msg);
    sprintf(db_msg,"Not connected.");
    XtVaSetValues(AppWidgetsPtr->message,
		  XtVaTypedArg, XmNlabelString, XmRString,
		  db_msg, strlen(db_msg)+1, NULL);
    connected = 0;
    DB_UnGrab();
    return 0;
  }    
  sprintf(db_msg,"Connected to database '%s'.", dbname); 
  connected = 1;
  XtVaSetValues(AppWidgetsPtr->message,
		  XtVaTypedArg, XmNlabelString, XmRString,
		  db_msg, strlen(db_msg)+1, NULL);

  DB_UnGrab();

  return 1;
}

/************************************************************************/
/* Function: DB_Close                                                   */
/* Purpose : kills connection to postgres database                      */
/* Params  :                                                            */
/* Returns :                                                            */
/* Notes   :                                                            */
/************************************************************************/

void DB_Close(void)
{
  /* disconnect from database */
  if(connected)
    PQfinish(db);
}

/************************************************************************/
/* Function: DB_SubmitQy                                                */
/* Purpose : submits SQL window contents to postgres database           */
/* Params  :                                                            */
/* Returns : 1 on SUCCESS / 0 on FAILURE                                */
/* Notes   :                                                            */
/************************************************************************/

int DB_SubmitQy(void)
{
  char *qy_ptr;
  int buf_pos;
  int qy_pos;
  int qy_len;
  int selected = 0;
  char db_msg[ERR_MSG_SIZE];
  char qy_buffer[QY_BUFFER_SIZE];
  PGresult* results;
  PGnotify* notify;

  if (!connected) {
    sprintf(db_msg,"No Connection to database.");
    ErrorMsg("Query", db_msg);
    return 0;
  }

  if((char*)XmTextGetSelection(AppWidgetsPtr->sqlwindow)!= NULL){
    qy_ptr = (char*)doubleTrim((char*)XmTextGetSelection(AppWidgetsPtr->sqlwindow));
    selected = 1;
  }
  else
    qy_ptr = (char*)doubleTrim((char*)XmTextGetString(AppWidgetsPtr->sqlwindow));
  
  if((qy_len = strlen(qy_ptr)) == 0){
    if(selected)
      XtFree(qy_ptr);
    return 0;
  }
 
  qy_pos = 0;

  DB_Grab();

  while(qy_pos < qy_len){
    buf_pos = 0;

    while((qy_ptr[qy_pos] != ';') && (qy_pos < qy_len)){
      qy_buffer[buf_pos++] = qy_ptr[qy_pos++];
      if(strlen(qy_buffer) > (QY_BUFFER_SIZE - 2)){
	sprintf(db_msg,"Query length exceeds max. query size, truncated at %d\n", 
		QY_BUFFER_SIZE);
	DB_WriteToResult(db_msg, 0, NULL);
	break;
      }
    }

    qy_pos++;
    qy_buffer[buf_pos++] = ';';
    qy_buffer[buf_pos] = '\0';

    results = PQexec(db, (char*)doubleTrim(qy_buffer));
    if (results == NULL) {
      DB_UnGrab();
      DB_WriteToResult(PQerrorMessage(db), 0, NULL);
      return 0;
    }
    
    switch (PQresultStatus(results)) {
    case PGRES_TUPLES_OK:
      DB_PrintTuples(qy_buffer,
		     results,
		     spool_file,
		     XmToggleButtonGetState(AppWidgetsPtr->tglspool),  
		     XmToggleButtonGetState(AppWidgetsPtr->tglcol),
		     XmToggleButtonGetState(AppWidgetsPtr->tglecho),
		     col_width,
		     GetColSeparator()
		     );
      PQclear(results);
      break;
    case PGRES_EMPTY_QUERY:
      /* do nothing */
      break;
    case PGRES_COMMAND_OK:
      sprintf(db_msg,"%s\n\n",PQcmdStatus(results));
      DB_WriteToResult(db_msg, 0, NULL);
      break;
    case PGRES_COPY_OUT:
      DB_HandleCopyOut(results);
      PQclear(results);
      break;
    case PGRES_COPY_IN:
      DB_HandleCopyIn(results);
      PQclear(results);
      break;
    case PGRES_NONFATAL_ERROR:
    case PGRES_FATAL_ERROR:
    case PGRES_BAD_RESPONSE:
      DB_WriteToResult(PQerrorMessage(db), 0, NULL);
      break;
    } 
    
    /* check for asynchronous returns */
    notify = PQnotifies(db);
    if (notify) {
      sprintf(db_msg,"ASYNC NOTIFY of '%s' from backend pid '%d' received", 
	      notify->relname, notify->be_pid);
      DB_WriteToResult(db_msg, 0, NULL);
      free(notify);
    }
  }
  if(selected)
      XtFree(qy_ptr);
  DB_UnGrab();
  return 1;
}

/************************************************************************/
/* Function: DB_OpenFile                                                */
/* Purpose : opens a file into the SQL window                           */
/* Params  : file : string w/ filename                                  */
/* Returns : 1 on SUCCESS / 0 on FAILURE                                */
/* Notes   :                                                            */
/************************************************************************/

int DB_OpenFile(char *file)
{
  FILE *sqlf;
  char db_msg[ERR_MSG_SIZE];
  char dataString[DATA_SIZE];
  XmTextSource txt_src;
  LLISTbuffer *tmp_buffer;

  if((sqlf = fopen(file, "rw")) == NULL){
    sprintf(db_msg, "Error opening: %s", file);
    ErrorMsg("Open File", db_msg);
    return 0;
  }

  if((tmp_buffer = LLIST_Insert(0, file, buffer_tail)) == NULL){
    sprintf(db_msg, "Not enough memory to open file :\n%s", file);
    ErrorMsg("Open File", db_msg);
    return 0;
  }

  DB_Grab();

  while(fgets(dataString, sizeof(dataString), sqlf) != NULL){
    DB_WriteToBuffer(dataString, tmp_buffer->buffer);
  }

  DB_UnGrab();

  if(fclose(sqlf) != 0){
    sprintf(db_msg, "Error closing file:\n%s", file);
    ErrorMsg("Open File", db_msg);
    return 0;
  }
  
  buffer_curr = DB_SetBuffer(tmp_buffer);
  return 1;
}

/************************************************************************/
/* Function: DB_SaveFile                                                */
/* Purpose : saves a buffer into its source file                        */
/* Params  : buffer : ptr to buffer to save                             */
/* Returns : 1 on SUCCESS / 0 on FAILURE                                */
/* Notes   :                                                            */
/************************************************************************/

int DB_SaveFile(LLISTbuffer *buffer)
{
  FILE *sqlf;
  char *data;
  char db_msg[ERR_MSG_SIZE];

  if((sqlf = fopen(buffer->filename, "w+")) == NULL){
    sprintf(db_msg, "Error opening: %s", buffer->filename);
    ErrorMsg("Save", db_msg);
    return 0;
  }

  data = XmTextGetString(buffer->buffer);

  DB_Grab();

  fputs(data, sqlf);
  fflush(sqlf);

  DB_UnGrab();

  if(fclose(sqlf) != 0){
    sprintf(db_msg, "Error closing file: %s", buffer->filename);
    ErrorMsg("Save", db_msg);
    return 0;
  }
  buffer->modified = 0;
  DB_SetTitle(buffer->filename);
  sprintf(db_msg, "Saved file: %s", buffer->filename);
  XtVaSetValues(AppWidgetsPtr->message,
		XtVaTypedArg, XmNlabelString, XmRString,
		db_msg, strlen(db_msg)+1, NULL);

  return 1;
}

/************************************************************************/
/* Function: DB_PrintTuples                                             */
/* Purpose : prints query results to selected destination               */
/* Params  : qy : string w/ qy                                          */
/*           res: query result struct                                   */
/*           fout: string w/ file to write to                           */
/*           Spool: spooling flag 0=FALSE / 1=TRUE                      */
/*           PrintAttNames: print attribute names 0=FALSE / 1=TRUE      */
/*           TerseOutput: print terse output 0=FALSE / 1=TRUE           */
/*           Echo: echo query 0=FALSE / 1=TRUE                          */
/*           colWidth: width of output columns                          */
/* Returns :                                                            */
/* Notes   :                                                            */
/************************************************************************/

void DB_PrintTuples(char *qy, PGresult *res, char *fout, int Spool, int PrintAttNames, 
		    int Echo, int colWidth, char sep)
{
  FILE *spoolf;
  int nFields; 
  int nTups;
  int i,j;
  char formatString[80];
  char dataString[DATA_SIZE];
  
  char *tborder = NULL;
  
  nFields = PQnfields(res);
  nTups = PQntuples(res);

  if(Spool){
    if((spoolf = fopen(fout, "w+")) == NULL){
      sprintf(dataString, "Error opening/creating file: %s\n", fout);
      DB_WriteToResult(dataString, 0, NULL);
      return;
    }
  }

  if(Echo){
    sprintf(dataString, "QUERY: %s\n\n", 
	    (char *)doubleTrim(qy));
    DB_WriteToResult(dataString, Spool, spoolf);
  }

  if (colWidth > 0) {
    if(sep == '\0')
       sprintf(formatString,"%%s%%-%ds", colWidth);
    else
      sprintf(formatString,"%%s%%-%ds%c", colWidth, sep);
  } else
    sprintf(formatString,"%%s%%s%c", sep);
  
  if ( nFields > 0 ) {  /* only print tuples with at least 1 field.  */
    
    if (PrintAttNames)
      {
	int width;
	width = nFields * colWidth;
	tborder = XtMalloc (width+1);
	for (i = 0; i <= width; i++) 
	  tborder[i] = '-';
	tborder[i] = '\0';
      }
    
    for (i=0; i < nFields; i++) {
      if (PrintAttNames) {
	sprintf(dataString,formatString,
		"", PQfname(res, i));
	if(i == (nFields - 1)) 
	  dataString[strlen(dataString) - 1] = '\0';
	DB_WriteToResult(dataString, Spool, spoolf);
      }
    }
    
    if (PrintAttNames) {
      sprintf(dataString,"\n%s\n", tborder);
      DB_WriteToResult(dataString, Spool, spoolf);
    }
    
    for (i = 0; i < nTups; i++) { 
      if(XmTextGetLastPosition(AppWidgetsPtr->resultwindow) > RSLT_BUFFER_SIZE)
	DB_ShrinkBuffer(AppWidgetsPtr->resultwindow);

      for (j = 0; j < nFields; j++) {
	char *pval = PQgetvalue(res,i,j);
	sprintf(dataString, formatString,
		"", pval ? pval : "");
	if(j == (nFields - 1)) 
	  dataString[strlen(dataString) - 1] = '\0';
	DB_WriteToResult(dataString, Spool, spoolf);
      }
      sprintf(dataString,"\n");
      DB_WriteToResult(dataString, Spool, spoolf);
    }
    DB_WriteToResult("\n", Spool, spoolf);
    XtFree(tborder);

    if(Spool){
      if(fclose(spoolf) != 0){
	sprintf(dataString, "Error closing file: %s\n", fout);
	DB_WriteToResult(dataString, 0, NULL);
	return;
      }
      DB_WriteToResult("Query finished.\n", 0, NULL);  
    }
  }
}

/************************************************************************/
/* Function: DB_WriteToResult                                           */
/* Purpose : writes data to result window                               */
/* Params  : data : string w/ data to write                             */
/*           spool: spool flag 0=FALSE / 1=TRUE                         */
/*           file : spool file (FILE*)                                  */
/* Returns :                                                            */
/* Notes   :                                                            */
/************************************************************************/

void DB_WriteToResult(char *data, int spool, FILE *file)
{
  XmTextPosition ins_pos;

  if(spool)
    fprintf(file, data);
  else{
    ins_pos = XmTextGetLastPosition(AppWidgetsPtr->resultwindow);
    XmTextInsert(AppWidgetsPtr->resultwindow, ins_pos, data);
    XmTextShowPosition(AppWidgetsPtr->resultwindow,
                       XmTextGetLastPosition(AppWidgetsPtr->resultwindow)+1);
  }
}

/************************************************************************/
/* Function: DB_WriteToSQL                                              */
/* Purpose : writes data to SQL window                                  */
/* Params  : data : string w/ data to write                             */
/* Returns :                                                            */
/* Notes   :                                                            */
/************************************************************************/

void DB_WriteToSQL(char *data)
{
  XmTextPosition ins_pos;

  ins_pos = XmTextGetLastPosition(AppWidgetsPtr->sqlwindow);
  XmTextInsert(AppWidgetsPtr->sqlwindow, ins_pos, data);
}

/************************************************************************/
/* Function: DB_WriteToBuffer                                           */
/* Purpose : writes data to text widget (buffer)                        */
/* Params  : data : string w/ data to write                             */
/*           w : text widget to write to (buffer)                       */
/* Returns :                                                            */
/* Notes   :                                                            */
/************************************************************************/

void DB_WriteToBuffer(char *data, Widget w)
{
  XmTextPosition ins_pos;

  ins_pos = XmTextGetLastPosition(w);
  XmTextInsert(w, ins_pos, data);
}

/************************************************************************/
/* Function: DB_OpenScratchBuffer                                       */
/* Purpose : opens a new scratch buffer                                 */
/* Params  :                                                            */
/* Returns : ptr to new buffer on SUCCESS / NULL on FAILURE             */
/* Notes   :                                                            */
/************************************************************************/

LLISTbuffer* DB_OpenScratchBuffer(void)
{
  char db_msg[ERR_MSG_SIZE];
  LLISTbuffer *tmp_buffer;

  if((tmp_buffer = LLIST_Insert(0, "scratch", buffer_tail)) == NULL){
    sprintf(db_msg, "Not enough memory to open buffer.");
    ErrorMsg("New", db_msg);
    return NULL;
  }
  else
    return tmp_buffer;
}

/************************************************************************/
/* Function: DB_SetBuffer                                               */
/* Purpose : sets a select buffer to current SQL window buffer          */
/* Params  : buffer : ptr to buffer to display                          */
/* Returns : ptr to new current buffer                                  */
/* Notes   :                                                            */
/************************************************************************/

LLISTbuffer* DB_SetBuffer(LLISTbuffer *buffer)
{
  XmTextSource sql_src;
  XmTextSource buffer_src;
 
  buffer_src = XmTextGetSource(buffer->buffer);
  XmTextSetSource(AppWidgetsPtr->sqlwindow, buffer_src, 0, 0);
 
  sql_src = XmTextGetSource(AppWidgetsPtr->sqlwindow);
  XmTextSetSource(buffer->buffer, sql_src, 0, 0);
 
  DB_SetTitle(buffer->filename);
 
  return buffer;
}

/************************************************************************/
/* Function: DB_SetTitle                                                */
/* Purpose : sets app's title window to passed string                   */
/* Params  : win_title : string w/ window title                         */
/* Returns :                                                            */
/* Notes   :                                                            */
/************************************************************************/

void DB_SetTitle(char *win_title)
{
  char title[MAX_PATH_LEN]= "MPSQL - ";

  XtVaSetValues(AppWidgetsPtr->shell,
		XmNtitle, strcat(title, win_title),
		NULL);

}

/************************************************************************/
/* Function: DB_DeleteBuffer                                            */
/* Purpose : deletes a buffer                                           */
/* Params  : buffer : ptr to buffer to delete                           */
/* Returns :                                                            */
/* Notes   :                                                            */
/************************************************************************/

void DB_DeleteBuffer(LLISTbuffer *buffer)
{
  if((LLIST_Count() - 1) == 0){
    DB_OpenScratchBuffer();
    buffer_curr = DB_SetBuffer(buffer_tail->prev);
  }
  else{
    if(buffer->prev == buffer_head)
      buffer_curr = DB_SetBuffer(buffer->next);
    else 
      buffer_curr = DB_SetBuffer(buffer->prev);
  }
  LLIST_Delete(buffer);
} 

/************************************************************************/
/* Function: DB_PrintBuffer                                             */
/* Purpose : prints contents of a buffer                                */
/* Params  : buffer : ptr to buffer to print                            */
/*           printer: ptr to printer command string to use              */
/* Returns :                                                            */
/* Notes   :                                                            */
/************************************************************************/

void DB_PrintBuffer(LLISTbuffer *buffer, char *printer)
{
  char tmp_file[MAX_PATH_LEN];
  char tmp_name[MAX_PATH_LEN];
  char print[MAX_PATH_LEN];
  FILE *sqlf;
  char *data;
  char db_msg[ERR_MSG_SIZE];

  sprintf(tmp_file, "%s", tmpnam(tmp_name));

  if((sqlf = fopen(tmp_file, "w+")) == NULL){
    sprintf(db_msg, "Error opening tmp file: %s", tmp_file);
    ErrorMsg("Print", db_msg);
    return;
  }

  data = XmTextGetString(buffer->buffer);

  fputs(data, sqlf);
  fflush(sqlf);

  if(fclose(sqlf) != 0){
    sprintf(db_msg, "Error closing tmp file: %s", tmp_file);
    ErrorMsg("Print", db_msg);
    return;
  }

  sprintf(print, "%s %s",
	  doubleTrim((char *)XmTextGetString(AppWidgetsPtr->printer)) ,tmp_file); 
  system(print);
  sprintf(print, "rm -f %s", tmp_file);
  system(print);
}

/************************************************************************/
/* Function: DB_ChkModBuffers                                           */
/* Purpose : checks the linked list for modified buffers                */
/* Params  :                                                            */
/* Returns : 0 all saved / 1 unsaved buffers                            */
/* Notes   :                                                            */
/************************************************************************/

int DB_ChkModBuffers(void)
{
  int i;
  LLISTbuffer *curr;

  for(i = 1; i <= LLIST_Count(); i++){
    curr = LLIST_Get(i);
    if(curr->modified == 1)
      return 1;
  }
  return 0;
}

/************************************************************************/
/* Function: DB_ShrinkBuffer                                            */
/* Purpose : removes text from top of specified text widget             */
/* Params  : w : text widget to remove text from                        */
/* Returns : nothing                                                    */
/* Notes   :                                                            */
/************************************************************************/

void DB_ShrinkBuffer(Widget w)
{
  int i;
  char *txt = XmTextGetString(w);

  while(XmTextGetLastPosition(w) >= RSLT_BUFFER_SIZE){
    i = 0;
    while(txt[i] != '\n') 
      i++;
    XmTextReplace(w, 0, ++i, "");
  }
}

/************************************************************************/
/* Function: DB_HandleCopyOut                                           */
/* Purpose : copies data out as specified by passed copy command        */
/* Params  : res: result set from copy command                          */
/* Returns : nothing                                                    */
/* Notes   :                                                            */
/************************************************************************/

void DB_HandleCopyOut(PGresult *res)
{
    bool copydone = false;
    char copybuf[COPYBUFSIZ];
    int ret;
    
    while (!copydone) {
	ret = PQgetline(res->conn, copybuf, COPYBUFSIZ);
	
	if (copybuf[0] == '.' && copybuf[1] =='\0') {
	    copydone = true;	/* don't print this... */
	} else {
	    fputs(copybuf, stdout);
	    switch (ret) {
	    case EOF:
		copydone = true;
	    case 0:
		fputc('\n', stdout);
		break;
	    case 1:
		break;
	    }
	}
    }
    fflush(stdout);
    PQendcopy(res->conn);
}

/************************************************************************/
/* Function: DB_HandleCopyIn                                            */
/* Purpose : copies data in as specified by passed copy command         */
/* Params  : res: result set from copy command                          */
/* Returns : nothing                                                    */
/* Notes   :                                                            */
/************************************************************************/

void DB_HandleCopyIn(PGresult *res)
{
    bool copydone = false;
    bool firstload;
    bool linedone;
    char copybuf[COPYBUFSIZ];
    char *s;
    int buflen;
    int c;
    
    fflush(stdin);
    if ((c = getc(stdin)) != '\n' && c != EOF) {
	(void) ungetc(c, stdin);
    }
    
    while (!copydone) {			/* for each input line ... */
	firstload = true;
	linedone = false;
	while (!linedone) {		/* for each buffer ... */
	    s = copybuf;
	    buflen = COPYBUFSIZ;
	    for (; buflen > 1 &&
		 !(linedone = (c = getc(stdin)) == '\n' || c == EOF);
		 --buflen) {
		*s++ = c;
	    }
	    if (c == EOF) {
		/* reading from stdin, but from a file */
		PQputline(res->conn, ".");
		copydone = true;
		break;
	    }
	    *s = '\0';
	    PQputline(res->conn, copybuf);
	    if (firstload) {
		if (!strcmp(copybuf, ".")) {
		    copydone = true;
		}
		firstload = false;
	    }
	}
	PQputline(res->conn, "\n");
    }
    PQendcopy(res->conn);
}

/************************************************************************/
/* Function: DB_TrapStderr                                              */
/* Purpose : Traps stderr for redirection to application                */
/* Params  : none                                                       */
/* Returns : nothing                                                    */
/* Notes   :                                                            */
/************************************************************************/

void DB_TrapStderr(void)
{
#ifndef AMIGA
  int errfd[2];
  (void) signal(SIGPIPE,SIG_IGN);

  if(pipe(errfd))
    return;

  dup2(errfd[1], fileno(stderr));
  close(errfd[1]);

  XtAppAddInput(app, errfd[0], (caddr_t) XtInputReadMask, 
		(XtInputCallbackProc) DB_RedirectStderr, NULL);
#endif
  return;
}

/************************************************************************/
/* Function: DB_RedirectStderr                                          */
/* Purpose : Callback for writing stderr to the result window           */
/* Params  : client_data : pointer to callback client data              */
/*           fd          : file handle pointer (stderr)                 */
/*           id          : XtAppAddInput process id pointer             */
/* Returns : nothing                                                    */
/* Notes   :                                                            */
/************************************************************************/

void DB_RedirectStderr(XtPointer client_data, int *fd, XtInputId *id)
{
  char buf[EXPLAINBUFSIZ];
  int nbytes;

  if((nbytes = read(*fd,buf,EXPLAINBUFSIZ - 1)) == (EOF))
    return;
  buf[nbytes] = '\0';
  if(nbytes)
    DB_WriteToResult(buf, 0, NULL);
  return;
}

/************************************************************************/
/* Function: DB_Grab                                                    */
/* Purpose : Grabs input events                                         */
/* Params  :                                                            */
/* Returns : nothing                                                    */
/* Notes   :                                                            */
/************************************************************************/

void DB_Grab(void)
{
  XDefineCursor(XtDisplay(AppWidgetsPtr->mainwindow),
		XtWindow(AppWidgetsPtr->mainwindow),
		XCreateFontCursor(XtDisplay(AppWidgetsPtr->mainwindow),
				  XC_watch));

  XtGrabButton(AppWidgetsPtr->mainwindow,
	       AnyButton,
	       AnyModifier,
	       TRUE,
	       ButtonPressMask|ButtonMotionMask|ButtonReleaseMask|
	       LeaveWindowMask|EnterWindowMask|FocusChangeMask,
	       GrabModeAsync,
	       GrabModeAsync,
	       None,
	       None);
}

/************************************************************************/
/* Function: DB_UnGrab                                                  */
/* Purpose : UnGrabs input events                                       */
/* Params  :                                                            */
/* Returns : nothing                                                    */
/* Notes   :                                                            */
/************************************************************************/

void DB_UnGrab(void)
{
  XtUngrabButton(AppWidgetsPtr->mainwindow, AnyButton, AnyModifier);
  XUndefineCursor(XtDisplay(AppWidgetsPtr->mainwindow),
		  XtWindow(AppWidgetsPtr->mainwindow));
}


