/* $Id: Clipboard.c,v 1.1 1997/04/15 10:09:26 archer Exp $
 *	CLIPBOARD.C - Control the clipboard selection
 *
 * This is always included, because the event dispatcher knows about
 * selections.
 */
#include <Widget/clipP.h>
#include <Widget/PerrorP.h>
#include <X11/Xatom.h>


/**
 ** Internal variables
 **/
static x11__handler	on_deselect;
static X11_widget	clip_origin;
static char		*clip_string;
static Atom		data_prop;
static int		clip_len;


/**
 ** Internal: INIT_ATOMS
 **	Internalize the atoms
 **/
static void init_atoms(void)
{
/*
 * Job already done?
 */
	if (!data_prop)
		return;
/*
 * Where I want the property to go!
 */
	data_prop = XInternAtom(x11__screen, "CLIP", False);
}


/** 
 ** X11_CLIPBOARD_OWNER
 **	The clipboard owner would like to be notified on any deselection
 **/
void x11__clipboard_owner(X11_widget wdg, x11__handler action)
{
/*
 * Set action of interest
 */
	if (action) {
		on_deselect = action;
		clip_origin = wdg;
	} else
/*
 * Remove action only if this IS the clipboard owner
 */
		if (clip_origin == wdg)
			on_deselect = 0;
}


/**
 ** X11_CLIPBOARD_STRING
 **	This string is the new clipboard selection
 **/
void x11__clipboard_string(char *s, int len)
{
/*
 * Copy the clipped string
 */
	if (clip_string)
		free(clip_string);
	if (len < 0)
		len = strlen(s);
	clip_string = malloc(len+1);
	if (!clip_string)
		X11_Perror("Allocating Clipboard");
	memcpy(clip_string, s, len);
	clip_string[len] = '\0';
	clip_len = len;
/*
 * Previous selection is no longer selected
 */
	if (on_deselect) {
		(*on_deselect)(clip_origin, (XEvent *)0);
		on_deselect = 0;
		clip_origin = 0;
	}
/*
 * Set myself as the selection owner
 */
	XSetSelectionOwner(x11__screen, XA_PRIMARY, x11__error_window,
								CurrentTime);
	if (XGetSelectionOwner(x11__screen, XA_PRIMARY) != x11__error_window) {
/*** HACK ***/
#ifdef DEBUGGING_X11
		fprintf(stderr, "Selection rejected!\n");
#endif
		return;
	}
}


/**
 ** X11_CLIPBOARD_REQUEST
 **	Reply to a clipboard contents request
 **/
void x11__clipboard_request(XSelectionRequestEvent *e)
{
XSelectionEvent	back;
#ifdef DEBUGGING_X11
printf("Clipboard requested\n");
#endif
/*
 * Prepare event back
 */
	back.type = SelectionNotify;
	back.requestor = e->requestor;
	back.selection = e->selection;
	back.target    = e->target;
	back.time      = e->time;
/*
 * Check for string selection
 */
	init_atoms();
	if (back.target != XA_STRING)
		back.property = None;
	else {
/*
 * We might be able to provide a string selection
 */
		back.property = e->property;
		XChangeProperty(x11__screen, back.requestor,
					back.property,
					back.selection,
					8, PropModeReplace,
					(unsigned char *)clip_string,
					clip_len);
	}
	XSendEvent(x11__screen, back.requestor, False, 0, (XEvent *)&back);
}


/**
 ** X11_CLIPBOARD_CLEAR
 **	We're no longer holding the clipboard
 **/
void x11__clipboard_clear(XEvent *e)
{
/*
 * Free allocated memory
 */
	if (clip_string) {
		free(clip_string);
		clip_string = 0;
	}
/*
 * Relinquish the selection ownership
 */
	if (on_deselect) {
		(*on_deselect)(clip_origin, (XEvent *)0);
		on_deselect = 0;
		clip_origin = 0;
#ifdef DEBUGGING_X11
printf("Clipboard released\n");
#endif
	}
}


/**
 ** Internal: NOTIFY_FILTER
 **	Filter for a SelectionNotify event
 **/
static Bool notify_filter(Display *dummy, XEvent *e, XPointer ignore)
{
	if (e->type == SelectionNotify)
		return True;
	return False;
}


/**
 ** X11_CLIPBOARD_GET
 **	Read the String selection
 **/
char *x11__clipboard_get(void)
{
static char	buffer[8192];
XEvent		event;
Atom		actual_type;
unsigned char	*prop;
unsigned long	nitems, bytes_after;
int		actual_format;
/*
 * Self clipboard? :-)
 */
	buffer[sizeof(buffer)-1] = '\0';
	if (clip_string) {
		strncpy(buffer, clip_string, sizeof(buffer)-1);
		return buffer;
	}
/*
 * Query the current selection owner
 */
	init_atoms();
	XConvertSelection(x11__screen, XA_PRIMARY, XA_STRING, data_prop,
				x11__error_window, CurrentTime);
/*
 * Wait for the SelectionNotify events
 */
	XIfEvent(x11__screen, &event, notify_filter, 0);
/*
 * No string available?
 */
	*buffer = '\0';
#ifdef DEBUGGING_X11
printf("Clipboard returned\n");
#endif
	if (event.xselection.property == None)
		return buffer;
#ifdef DEBUGGING_X11
printf("Clipboard is not empty\n");
#endif
/*
 * Recover property
 */
	if (XGetWindowProperty(x11__screen, event.xselection.requestor,
				event.xselection.property, 0, sizeof(buffer)/4,
				True, AnyPropertyType, &actual_type,
				&actual_format, &nitems, &bytes_after,
				&prop) != Success)
		return buffer;
	strncpy(buffer, prop, sizeof(buffer)-1);
	XFree(prop);
	return buffer;
}
