/* clipbrd.c  - clipboard functions for Motif programs  (cut/paste support)
   (C) A. Stochniol, 1991 - 1993
   These functions are needed only for Motif 1.0.
   For Motif 1.1 and later I am using new standard clipboard functions
   (therefore this file is compiled conditionally; alternatively you may
   delete that file from the make specification)
*/

#include <stdio.h>
#include <Xm/Xm.h>
/* I have left the above declarations outside #if because some compilers 
   complain about empty source files */

#if (XmVersion == 1000)
/* conditional Motif 1.0 compilation **/

#include <X11/Xatom.h>
#include <Xm/CutPaste.h>
#include <Xm/Text.h>

#include "clipbrd.h"

#define 	AS_CLBOARD_FORMAT        "STRING"

extern Widget	toplevel;

/*-------------------------------------------------------------
**	CopyStringToClipboard
**		Copy the string str to the clipboard.
**		Returns True when successful.
**
**  Note for clipboard functions:  those functions need display and window
**  parameters and they are used to identify the clipboard owner. They should
**  always be the same for one application. So to safeguard this we are using
**  internally a top-level application shell obtained as a global variable (its
**  name was assumed to be: "toplevel"). The display and the window are obtained
**  using XtDisplay and XtWindow, respectively.
**
*/
#ifdef _NO_PROTO
Boolean CopyStringToClipboard(str, time)
   char *str;
   Time time;
#else  /* _NO_PROTO */
Boolean CopyStringToClipboard(char *str, Time time)
#endif
{

   long item_id = 0; 		/* clipboard item id */
   int data_id = 0;			/* clipboard data id */
   int status = 0;			/* clipboard status  */
   int RETRY_COUNT = 1000;		/* to avoid blocking infinitely if another
					   client does not release the clipboard
					   lock an upper bound for the re-tries
					   is used */
   char *clipboard_warning = "Warning: copy failed, clipboard locked !\n";
   int retries;
   XmStringCharSet charset = (XmStringCharSet) XmSTRING_DEFAULT_CHARSET; /* use default */
   XmString clip_label;

   /* using the clipboard facilities, copy the string str to the clipboard */
   if (str != NULL) {
	clip_label = XmStringCreateLtoR ("AS_APPLICATION", charset);
	/* start copy to clipboard, and continue till
	   a sucessful start copy is made */
	retries = RETRY_COUNT;
	do
	{
	    status = XmClipboardStartCopy (XtDisplay(toplevel), XtWindow(toplevel),
			clip_label, time, toplevel, NULL, &item_id);
	} while (status != ClipboardSuccess && (retries-- >= 0));
	if(retries <= 0) { fprintf(stderr, clipboard_warning); return(False); }

	/* move the data to the clipboard, and continue till
	   a sucessful copy is made */
	retries = RETRY_COUNT;
	do
	{
	    status = XmClipboardCopy (XtDisplay(toplevel), XtWindow(toplevel),
		      item_id, AS_CLBOARD_FORMAT, str, (long)strlen(str)+1, 0, &data_id);
	} while (status != ClipboardSuccess && (retries-- >= 0));
	if(retries <= 0) { fprintf(stderr, clipboard_warning); return(False); }

	/* end the copy to the clipboard and continue till
	   a sucessful end copy is made */

	retries = RETRY_COUNT;
	do
	{
	    status = XmClipboardEndCopy (XtDisplay(toplevel), XtWindow(toplevel),
					 item_id);
	} while (status != ClipboardSuccess && (retries-- >= 0));
	if(retries <= 0) { fprintf(stderr, clipboard_warning); return(False); }

	return(True);		/* copy was successful */


   }
   else return(False);

}  /* CopyStringToClipboard */

/*-------------------------------------------------------------
**	GetStringFromClipboard
**		get string from the clipboard (returns string when successful)
*/
char * GetStringFromClipboard()
{
   /* retrieve the current data from the clipboard */

   char *buffer=NULL;
   int status = 0;			      /* clipboard status	 */
   int RETRY_COUNT = 1000;		/* to avoid blocking infinitely if another
					   client does not release the clipboard
					   lock an upper bound for the re-tries
					   is used */
   char *clipboard_warning = "Warning: paste failed, clipboard locked !\n";
   int retries;
   unsigned long length;				      /* length of buffer     	 */
   unsigned long outlength = 0;			      /* length of bytes copied	 */
   int private_id = 0;			      /* id of item on clipboard */

   /* find the length of the paste item, continue till the length is found */
   retries = RETRY_COUNT;
   do
   {
	status = XmClipboardInquireLength(XtDisplay(toplevel), XtWindow(toplevel),
				      AS_CLBOARD_FORMAT, &length);
	if (status == ClipboardNoData) { length = 0;  break; }
   } while (status != ClipboardSuccess && (retries-- >= 0));
   if(retries <= 0) { fprintf(stderr, clipboard_warning); return(NULL); }

   if (length == 0) { fprintf(stderr,
	 "Warning: paste failed, no items to paste.\n"); return(NULL); }

   /* malloc to necessary space */
   buffer = XtMalloc(length);

   status = XmClipboardRetrieve (XtDisplay(toplevel), XtWindow(toplevel), AS_CLBOARD_FORMAT,
				 buffer, length, &outlength, &private_id);

   /*  !!!!! Dialogs need to be added to indicate errors in pasting */
   if (status != ClipboardSuccess) {
	fprintf(stderr, "Warning: paste failed, status = %d\n", status);
	return(NULL);
   }
   return(buffer);

}  /* GetStringFromClipboard */


/*-------------------------------------------------------------
**	DeletePrimarySelection
**		Deletes the primary selection.
*/
#ifdef _NO_PROTO
void DeletePrimarySelection(text)
   Widget text;
#else  /* _NO_PROTO */
void DeletePrimarySelection(Widget text)
#endif
{
   XClientMessageEvent cm;

   /* send a client message to the text widget
      to delete the current selection */
   cm.type = 	     ClientMessage;
   cm.display =      XtDisplay(text);
   cm.message_type = XmInternAtom(XtDisplay(text), "KILL_SELECTION", FALSE);
   cm.window = 	     XtWindow(text);
   cm.format = 	     32;
   cm.data.l[0] =    XA_PRIMARY;
   XSendEvent(XtDisplay(text), cm.window, TRUE, NoEventMask, &cm);

}  /* DeletePrimarySelection */

/*-------------------------------------------------------------
**	PasteItemFromClipboard
**		paste item from the clipboard to the current cursor location
*/
#ifdef _NO_PROTO
void PasteItemFromClipboard(text)
   Widget text;
#else  /* _NO_PROTO */
void PasteItemFromClipboard(Widget text)
#endif
{
   /* retrieve the current data from the clipboard
      and paste it at the current cursor position */

   char *buffer;			      /* temporary text buffer 	 */
   XmTextPosition cursorPos;		      /* text cursor position 	 */
   Arg al[10];				      /* arg list	      	 */

   /* get the string from the clipboard; if successful paste it */
   if( (buffer = GetStringFromClipboard()) != NULL )
   {
	   /* get cursor position for pasting */
	   XtSetArg(al[0], XmNcursorPosition, &cursorPos);
	   XtGetValues(text, al, 1);

	   /* add new text */
	   XmTextReplace(text, cursorPos, cursorPos, buffer);

	   /****8.04.92* free the memory allocated (inside GetString...) for temporary text buffer */
	   XtFree(buffer);
   }

}  /* PasteItemFromClipboard */


/* end of conditional Motif 1.0 compilation */
#endif
