/*
 * chain.c --
 *
 *	This module manages the event queues.  There are three
 *	event queues that are used in this library: an X event
 *	queue, a timer event queue, and a file event queue that
 *	is mainly used for sockets.
 *	
 * Copyright (c) 1994 Software Research Associates, Inc.
 *
 * Permission to use, copy, modify, and distribute this software and its
 * documentation for any purpose and without fee is hereby granted, provided
 * that the above copyright notice appear in all copies and that both that
 * copyright notice and this permission notice appear in supporting
 * documentation, and that the name of Software Research Associates not be
 * used in advertising or publicity pertaining to distribution of the
 * software without specific, written prior permission.  Software Research
 * Associates makes no representations about the suitability of this software
 * for any purpose.  It is provided "as is" without express or implied
 * warranty.
 */

#include "xlibInt.h"

/*
 *----------------------------------------------------------------------
 *
 * peekEvent --
 *
 *	Copies an X event, if available, without removing it from
 *	the X event queue.
 *
 * Results:
 *	NULL if no events are in the queue, a filled in 'event'
 *	if there was at least one event in the X event queue.
 *
 * Side Effects:
 *	None
 *
 *----------------------------------------------------------------------
 */
XEvent *
peekEvent(Display *display, _XQEvent *cPtr, XEvent *event)	
{
    if (cPtr == display->head) {
	return NULL;
    }

    memcpy(event, &cPtr->event, sizeof(XEvent));
    return event;
}

/*
 *----------------------------------------------------------------------
 *
 * peekFileEvent --
 *
 *	Copies a file event, if available, without removing it from
 *	the file event queue.
 *
 * Results:
 *	NULL if no events are in the queue, a filled in 'event'
 *	if there was at least one event in the queue.
 *
 * Side Effects:
 *	None
 *
 *----------------------------------------------------------------------
 */
XEvent *
peekFileEvent(Display *display, _XQEvent *cPtr, XEvent *event)	
{
    if (cPtr == display->filehead) {
	return NULL;
    }

    memcpy(event, &cPtr->event, sizeof(XEvent));
    return event;
}

/*
 *----------------------------------------------------------------------
 *
 * peekTimerEvent --
 *
 *	Copies a timer event, if available, without removing it from
 *	the timer event queue.
 *
 * Results:
 *	NULL if no events are in the queue, a filled in 'event'
 *	if there was at least one event in the queue.
 *
 * Side Effects:
 *	None
 *
 *----------------------------------------------------------------------
 */
XEvent *
peekTimerEvent(Display *display, _XQEvent *cPtr, XEvent *event)	
{
    if (cPtr == display->timerhead) {
	return NULL;
    }

    memcpy(event, &cPtr->event, sizeof(XEvent));
    return event;
}

/*
 *----------------------------------------------------------------------
 *
 * discardEvent --
 *
 *	Deletes the first event from the X event queue
 *
 * Results:
 *	None
 *
 * Side Effects:
 *	None
 *
 *----------------------------------------------------------------------
 */
void
discardEvent(Display *display, _XQEvent *cPtr)
{
    cPtr->prev->next = cPtr->next;
    cPtr->next->prev = cPtr->prev;
    display->qlen--;

    free(cPtr);
}

/*
 *----------------------------------------------------------------------
 *
 * discardFileEvent --
 *
 *	Deletes the first event from the X event queue
 *
 * Results:
 *	None
 *
 * Side Effects:
 *	None
 *
 *----------------------------------------------------------------------
 */
void
discardFileEvent(Display *display, _XQEvent *cPtr)
{
    cPtr->prev->next = cPtr->next;
    cPtr->next->prev = cPtr->prev;
    display->fileqlen--;

    free(cPtr);
}

/*
 *----------------------------------------------------------------------
 *
 * discardTimerEvent --
 *
 *	Deletes the first event from the X event queue
 *
 * Results:
 *	None
 *
 * Side Effects:
 *	None
 *
 *----------------------------------------------------------------------
 */
void
discardTimerEvent(Display *display, _XQEvent *cPtr)
{
    cPtr->prev->next = cPtr->next;
    cPtr->next->prev = cPtr->prev;
    display->timerqlen--;

    free(cPtr);
}

/*
 *----------------------------------------------------------------------
 *
 * getEvent --
 *
 *	Copies an X event, if available, and removes it from
 *	the X event queue.
 *
 * Results:
 *	NULL if no events are in the queue, a filled in 'event'
 *	if there was at least one event in the queue.
 *
 * Side Effects:
 *	None
 *
 *----------------------------------------------------------------------
 */
XEvent *
getEvent(Display *display, XEvent *event)	
{
    _XQEvent *cPtr;
    if (display->qlen == 0) {
	return NULL;
    }
    cPtr = display->head->next;
    memcpy(event, &cPtr->event, sizeof(XEvent));

    cPtr->prev->next = cPtr->next;
    cPtr->next->prev = cPtr->prev;
    display->qlen--;

    free(cPtr);
    return event;
}

/*
 *----------------------------------------------------------------------
 *
 * getFileEvent --
 *
 *	Copies a file event, if available, and removes it from
 *	the file event queue.
 *
 * Results:
 *	NULL if no events are in the queue, a filled in 'event'
 *	if there was at least one event in the queue.
 *
 * Side Effects:
 *	None
 *
 *----------------------------------------------------------------------
 */
XEvent *
getFileEvent(Display *display, XEvent *event)	
{
    _XQEvent *cPtr;
    if (display->fileqlen == 0) {
	return NULL;
    }
    cPtr = display->filehead->next;
    memcpy(event, &cPtr->event, sizeof(XEvent));

    cPtr->prev->next = cPtr->next;
    cPtr->next->prev = cPtr->prev;
    display->fileqlen--;

    free(cPtr);
    return event;
}

/*
 *----------------------------------------------------------------------
 *
 * getTimerEvent --
 *
 *	Copies a timer event, if available, and removes it from
 *	the timer event queue.
 *
 * Results:
 *	NULL if no events are in the queue, a filled in 'event'
 *	if there was at least one event in the queue.
 *
 * Side Effects:
 *	None
 *
 *----------------------------------------------------------------------
 */
XEvent *
getTimerEvent(Display *display, XEvent *event)	
{
    _XQEvent *cPtr;
    if (display->timerqlen == 0) {
	return NULL;
    }
    cPtr = display->timerhead->next;
    memcpy(event, &cPtr->event, sizeof(XEvent));

    cPtr->prev->next = cPtr->next;
    cPtr->next->prev = cPtr->prev;
    display->timerqlen--;

    free(cPtr);
    return event;
}

/*
 *----------------------------------------------------------------------
 *
 * putEvent --
 *
 *	Creates a duplicate event of the one passed in, and appends this
 *	to the end of the X event queue.
 *
 * Results:
 *	The new event or NULL if the malloc failed.
 *
 * Side Effects:
 *	None
 *
 *----------------------------------------------------------------------
 */
_XQEvent *
putEvent(Display *display, XEvent *event)
{
    _XQEvent *cPtr, *head;

    cPtr = (_XQEvent *) malloc(sizeof(_XQEvent));
    if (cPtr == NULL) {
	return NULL;
    }

    display->qlen++;
    head = display->head;
    cPtr->next = head;
    cPtr->prev = head->prev;
    head->prev->next = cPtr;
    head->prev = cPtr;

    memcpy(&cPtr->event, event, sizeof(XEvent));

    return cPtr;
}

/*
 *----------------------------------------------------------------------
 *
 * putFileEvent --
 *
 *	Creates a duplicate event of the one passed in, and appends this
 *	to the end of the file event queue.
 *
 * Results:
 *	The new event or NULL if the malloc failed.
 *
 * Side Effects:
 *	None
 *
 *----------------------------------------------------------------------
 */
_XQEvent *
putFileEvent(Display *display, XEvent *event)
{
    _XQEvent *cPtr, *head;

    cPtr = (_XQEvent *) malloc(sizeof(_XQEvent));
    if (cPtr == NULL) {
	return NULL;
    }

    display->fileqlen++;
    head = display->filehead;
    cPtr->next = head;
    cPtr->prev = head->prev;
    head->prev->next = cPtr;
    head->prev = cPtr;

    memcpy(&cPtr->event, event, sizeof(XEvent));

    return cPtr;
}

/*
 *----------------------------------------------------------------------
 *
 * putEvent --
 *
 *	Creates a duplicate event of the one passed in, and appends this
 *	to the end of the timer event queue.
 *
 * Results:
 *	The new event or NULL if the malloc failed.
 *
 * Side Effects:
 *	None
 *
 *----------------------------------------------------------------------
 */
_XQEvent *
putTimerEvent(Display *display, XEvent *event)
{
    _XQEvent *cPtr, *head;

    cPtr = (_XQEvent *) malloc(sizeof(_XQEvent));
    if (cPtr == NULL) {
	return NULL;
    }

    display->timerqlen++;
    head = display->timerhead;
    cPtr->next = head;
    cPtr->prev = head->prev;
    head->prev->next = cPtr;
    head->prev = cPtr;

    memcpy(&cPtr->event, event, sizeof(XEvent));

    return cPtr;
}


/*
 *----------------------------------------------------------------------
 *
 * putEvent --
 *
 *	Creates a duplicate event of the one passed in, and inserts this
 *	to the at the beginning of the X event queue.
 *
 * Results:
 *	The new event or NULL if the malloc failed.
 *
 * Side Effects:
 *	None
 *
 *----------------------------------------------------------------------
 */
_XQEvent *
putbackEvent(Display *display, XEvent *event)
{
    _XQEvent *cPtr, *head;

    cPtr = (_XQEvent *) malloc(sizeof(_XQEvent));
    if (cPtr == NULL) {
	return NULL;
    }

    memcpy(&(cPtr->event), event, sizeof(XEvent));

    display->qlen++;
    head = display->head;
    cPtr->next = head->next;
    cPtr->prev = head;
    head->next->prev = cPtr;
    head->next = cPtr;

    return cPtr;
}
