/*
 * xevent.c --
 *
 * 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" 

int
XFileEventsQueued(Display *display, int mode, int flags)
{
    MSG msg;
    XEvent event;
    int len;

    if (flags == 0) {
	flags = X_Queue;
    }

    len = 0;
    if (mode != QueuedForceReading) {
	if (flags & X_Queue) {
	    len += display->qlen;
	}
	if (flags & File_Queue) {
	    len += display->fileqlen;
	}
	if (flags & Timer_Queue) {
	    len += display->timerqlen;
	}
	if (len > 0 || mode == QueuedAlready) {
	    return len;
	}
    }
    
    while (1) {
	if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) == 0) {
	    len = 0;
	    if (flags & X_Queue) {
		len += display->qlen;
	    }
	    if (flags & File_Queue) {
		len += display->fileqlen;
	    }
	    if (flags & Timer_Queue) {
		len += display->timerqlen;
	    }
	    return len;
	}
	if (msg.hwnd == GetPostWindow() 
	   || (msg.message == WM_KEYDOWN 
	       && (msg.wParam == VK_NUMLOCK
		   || msg.wParam == VK_CAPITAL
		   || msg.wParam == VK_SCROLL)))
	    TranslateMessage(&msg);

	DispatchMessage(&msg);
	if (msg3event(display, &msg, &event)) {
	    if (event.type == SocketNotify) {
		putFileEvent(display, &event);
	    } else if (event.type == TimerNotify) {
		putTimerEvent(display, &event);
	    } else {
		putEvent(display, &event);
	    }
	}
    }
    /* NOTREACHED */
    return 1;
}

int
XEventsQueued(Display *display, int mode)
{
    return XFileEventsQueued(display, mode, X_Queue);
}

void
XNextFileEvent(Display *display, XEvent *report, int flags)
{
    MSG msg;

    if (flags == 0) {
	flags = X_Queue;
    }

    while (1) {
	if (flags & X_Queue && display->qlen > 0) {
	    getEvent(display, report);
	    display->last_request_read = report->xany.serial;
	    return;
	}
	if (flags & File_Queue && display->fileqlen > 0) {
	    getFileEvent(display, report);
	    display->last_request_read = report->xany.serial;
	    return;
	}
	if (flags & Timer_Queue && display->timerqlen > 0) {
	    getTimerEvent(display, report);
	    display->last_request_read = report->xany.serial;
	    return;
	}

	GetMessage(&msg, NULL, 0, 0);
	if (msg.hwnd == GetPostWindow() 
	   || (msg.message == WM_KEYDOWN 
	       && (msg.wParam == VK_NUMLOCK
		   || msg.wParam == VK_CAPITAL
		   || msg.wParam == VK_SCROLL)))
	    TranslateMessage(&msg);
	DispatchMessage(&msg);
	if (msg3event(display, &msg, report)) {
	    if (report->type == SocketNotify && !(flags & File_Queue)) {
		putFileEvent(display, report);
	    } else if (report->type == TimerNotify && !(flags & Timer_Queue)) {
		putTimerEvent(display, report);
	    } else if (report->type != SocketNotify &&
		       report->type != TimerNotify &&
		       ! (flags & X_Queue))
	    {
		putEvent(display, report);
	    } else {
		display->last_request_read = report->xany.serial;
		return;
	    }
	}
    }
}   

void
XNextEvent(Display *display, XEvent *report)
{
    XNextFileEvent(display, report, X_Queue);
}

/*
 * Process a windows message.  This function was going to be used by
 * the socket blocking hook, but that hook never got called.  Now it
 * is not used, but there may be reason to leave it here for now.
 */
void
XNextWindowsMessage(Display *display)
{
    MSG msg;
    XEvent event;

    GetMessage(&msg, NULL, 0, 0);
    if( msg.hwnd == GetPostWindow() 
       || (msg.message == WM_KEYDOWN 
	   && (msg.wParam == VK_NUMLOCK
	       || msg.wParam == VK_CAPITAL
	       || msg.wParam == VK_SCROLL)))
	TranslateMessage(&msg);
    DispatchMessage(&msg);
    if (msg3event(display, &msg, &event)) {
	if (event.type == SocketNotify) {
	    putFileEvent(display, &event);
	} else if (event.type == TimerNotify) {
	    putTimerEvent(display, &event);
	} else {
	    putEvent(display, &event);
	}
    }
    return;
}
    
Bool
XCheckIfEvent(Display *display, XEvent *event_return, 	
	Bool (*predicate)( Display *, XEvent *, char * ),
	char *arg)
{
    _XQEvent *head, *chain;

    head = display->head;
    for (chain = head->next; chain != head; chain = chain->next) {
	if( !(*predicate)( display, &chain->event, arg ) )
	    /* unmatch */
	    continue;
	/* match, pick it up and discard */
	peekEvent(display, chain, event_return);
	discardEvent(display, chain);
	return TRUE;
    }
    /* No match */
    return FALSE;
}

void
XPutBackEvent(Display *display, XEvent *event)
{
    putbackEvent(display, event);
}

    
int	 
XCheckWindowEvent(Display *display, Window w, long mask, XEvent *event)
{
    int type;
    _XQEvent *cPtr, *head;

    head = display->head;
    if (XEventsQueued(display, QueuedForceReading)) {
	for (cPtr = head->next; cPtr != head; cPtr = cPtr->next) {
	    type = cPtr->event.type;
	    if (type == MapNotify || type == UnmapNotify 
		|| type == ConfigureNotify || type == DestroyNotify) {
		peekEvent(display, cPtr, event);
		discardEvent(display, cPtr);
		return 1;
	    }
	}
    }
    return 0;
}	
     
Status
XSendEvent(Display *display, Window w, Bool propagate, long event_mask, XEvent *event_send)
{
    XEvent e;

    display->request++;

    memcpy( &e, event_send, sizeof(e) );
    e.xany.send_event = TRUE;
    putEvent(display, &e);
    return Success;
}
