/*****************************************************************
 * 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 u_long _near ClosingClients, _near AllClients, _near WellKnownSockets;
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 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;
    long timeout;
    u_long timeouttime;
    OsCommPtr oc;
    Bool done, first;
    int nready = 0;
    u_long iflags, oflags;

    /* 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;) {
		iflags = 0;
		oflags = 0;
		net_select(31, &iflags, &oflags);
		if (iflags & ClosingClients)
		    FlushData(iflags & ClosingClients);
		if (oflags & WellKnownSockets)
		    EstablishNewConnections();

#ifdef X_PRINT_PORT
		if (print_open) {
		    if (iflags & PrinterSockets);
			print_open = PrintIt();
		} else {
		    if (oflags & PrinterSockets);
			print_open = PrintOpen();
		}
#endif
#ifdef XDMCP
		if (iflags & (1L << xdmcpSocket))
			XdmcpReceivePacket(xdmcpSocket);
#endif
		iflags &= AllClients;
		if (oneClient) {

		    if ((oneClient->flags & OS_REUSE) || 
			(iflags & (1L << oneClient->fd))) {
			    pClientsReady[nready++] = oneClient->client;
			    done = TRUE;
		    }
		} else
		for (i = 0; i < NPORTS; i++) {
		    char junk[256];

		    oc = MyPrivate[i];
		    if (!oc)
			continue;
#ifdef notdef
		    if (oc->flags & OS_CLOSING) {
			if (oc->tcpport.state == SCLOSED) {
				SoFree(i);
				MyPrivate[i] = 0;
				xfree(oc);
				if (!WellKnownOS[0] || !WellKnownOS[1])
				    reset_socket();
			} else {
				(void)SoRead(oc->fd, junk, sizeof junk);
			}
			continue;
		    }
#endif
		    if ((oc->flags & OS_REUSE) || 
			(iflags & (1L << oc->fd))) {
			    pClientsReady[nready++] = oc->client;
			    done = TRUE;
		    }
		}
		if (AnyClientsWriteBlocked)
		{

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

			oc = MyPrivate[i];
			if (!oc)
			    continue;
			if (!(oc->flags & OS_BLOCKED))
			    continue;
			FlushClient(oc, (char *)NULL, 0);
		    }
		}
		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;
}
