/*****************************************************************
 * OS Depedent input routines:
 *
 *  WaitForSomething
 *
 *****************************************************************/

#include "Xos.h"			/* for strings, fcntl, time */

#include <errno.h>
#include <stdio.h>
#include "X.h"
#include "misc.h"
#include "opaque.h"

#include <signal.h>
#include "dixstruct.h"
#include "osdep.h"

extern OsCommPtr near oneClient;
extern fd_set _near WriteBlockedSockets, _near AllSockets;
u_long near sleepcount;
extern int near screenIsSaved;
#ifdef X_PRINT_PORT
extern u_long _near PrinterSockets;
#endif
#ifdef XDMCP
extern int near xdmcpSocket;
#endif
extern int _near WellKnownSocket;

extern Bool near NewOutputPending;
extern Bool near AnyClientsWriteBlocked;
extern OsCommPtr near MyPrivate[NPORTS];

extern long TimeSinceLastInputEvent();

extern u_short near input_ready, near input_ref;

/*****************
 * WaitForSomething:
 *     Make the server suspend until there is
 *	1. data from clients or
 *	2. input events available or
 *	3. ddx notices something of interest (graphics
 *	   queue ready, etc.) or
 *	4. clients that have buffered replies/events are ready
 *
 *     If the time between INPUT events is
 *     greater than ScreenSaverTime, the display is turned off (or
 *     saved, depending on the hardware).  So, WaitForSomething()
 *     has to handle this also (that's why the select() has a timeout.
 *     For more info on ClientsWithInput, see ReadRequestFromClient().
 *     pClientsReady is a mask, the bits set are 
 *     indices into the o.s. depedent table of available clients.
 *     (In this case, there is no table -- the index is the socket
 *     file descriptor.)  
 *****************/

static long timeTilFrob = 0;		/* while screen saving */
static int print_open;

int
WaitForSomething(pClientsReady)
    int *pClientsReady;
{
    int i, nfds;
    long timeout;
    u_long timeouttime;
    OsCommPtr oc;
    Bool done, first;
    int nready = 0;
    fd_set iflags, oflags;
    struct timeval tv;

    /* We need a while loop here to handle 
       crashed connections and the screen saver timeout */
    for (;;)
    {
	    if (dispatchException)
		return nready;

            if (ScreenSaverTime)
	    {
                timeout = ScreenSaverTime - TimeSinceLastInputEvent();
	        if (timeout <= 0) /* may be forced by AutoResetServer() */
	        {
		    long timeSinceSave;

		    timeSinceSave = -timeout;
	            if ((timeSinceSave >= timeTilFrob) && (timeTilFrob >= 0))
                    {
		        SaveScreens(SCREEN_SAVER_ON, ScreenSaverActive);
			if (ScreenSaverInterval)
			    /* round up to the next ScreenSaverInterval */
			    timeTilFrob = ScreenSaverInterval *
				    ((timeSinceSave + ScreenSaverInterval) /
					    ScreenSaverInterval);
			else
			    timeTilFrob = -1;
		    }
    	            timeout = timeTilFrob - timeSinceSave;
		    if (timeTilFrob < 0)
			timeout = 0;
    	        }
 		else
 		{
		    if (timeout > ScreenSaverTime)
		        timeout = ScreenSaverTime;
	            timeTilFrob = 0;
		}
	    }
            else {
                timeout = 0;
		if (screenIsSaved == SCREEN_SAVER_ON)
			SaveScreens(SCREEN_SAVER_OFF, ScreenSaverReset);
	    }
	    if (NewOutputPending)
	    	FlushAllOutput();
	    for (done = FALSE, first = TRUE; !done;) {
		tv.tv_sec = 0;
		tv.tv_usec = 0;
		iflags = AllSockets;
		if (AnyClientsWriteBlocked) {
		    oflags = WriteBlockedSockets;
		    nfds = select(32, &iflags, &oflags, 0, &tv);
		} else {
		    nfds = select(32, &iflags, 0, 0, &tv);
		}
		if (nfds < 0) {
		    soperror("select");
		    break;
		}
		if (nfds && FD_ISSET(WellKnownSocket, &iflags))
		    EstablishNewConnections();

#ifdef X_PRINT_PORT
		if (print_open) {
		    if (nfds && FD_ISSET(PrinterSocket, &iflags))
			print_open = PrintIt();
		} else {
		    if (nfds && FD_ISSET(PrinterSocket, &iflags))
			print_open = PrintOpen();
		}
#endif
#ifdef XDMCP
		if (nfds && FD_ISSET(xdmcpSocket, &iflags));
			XdmcpReceivePacket(xdmcpSocket);
#endif
		for (i = 0; i < NPORTS; i++) {
		    oc = MyPrivate[i];
		    if (!oc)
			continue;
		    if (oneClient && oneClient != oc)
			continue;
		    if ((oc->flags & OS_MORE) ||
			nfds && FD_ISSET(oc->fd, &iflags)) {
			    pClientsReady[nready++] = oc->client;
			    done = TRUE;
		    }
		}
		if (AnyClientsWriteBlocked)
		{

		    AnyClientsWriteBlocked = FALSE;
		    for (i = 0; i < NPORTS; i++) {

			oc = MyPrivate[i];
			if (!oc)
			    continue;
			if (FD_ISSET(oc->fd, &oflags)) {
			    FD_CLR(oc->fd, &WriteBlockedSockets);
			    FlushClient(oc, (char *)NULL, 0);
/*
printf("flush %d\n", oc->fd);
*/
			}
if (FD_ISSET(oc->fd, &WriteBlockedSockets))
printf("can't write to %d\n", oc->fd);
		    }
		}
		if (input_ready != input_ref)
		    done = TRUE;
		if (first && !done) {
		    XdmcpBlockHandler(&timeout);
		    mouseBlockHandler();
		    if (timeout) {
			_disable();
			timeouttime = timeout + clock();
			_enable();
		    }
		    first = FALSE;
		}
		if (!done && timeout) {
		    _disable();
		    if (clock() >= timeouttime)
			    done = TRUE;
		    _enable();
		}
	    }
	    XdmcpWakeupHandler();
	    if (input_ready != input_ref || nready)
		break;
    }
    return nready;
}
