[email protected]
#include "SDL_config.h"
#include "SDL.h"
#include "SDL_syswm.h"
#include "SDL_sysevents.h"
#include "SDL_events_c.h"
#include "../timer/SDL_timer_c.h"
#if !SDL_JOYSTICK_DISABLED
#include "../joystick/SDL_joystick_c.h"
#endif
SDL_EventFilter SDL_EventOK = NULL;
Uint8 SDL_ProcessEvents[SDL_NUMEVENTS];
static Uint32 SDL_eventstate = 0;
#define MAXEVENTS	128
static struct {
	SDL_mutex *lock;
	int active;
	int head;
	int tail;
	SDL_Event event[MAXEVENTS];
	int wmmsg_next;
	struct SDL_SysWMmsg wmmsg[MAXEVENTS];
} SDL_EventQ;
static struct {
	SDL_mutex *lock;
	int safe;
} SDL_EventLock;
static SDL_Thread *SDL_EventThread = NULL;	
static Uint32 event_thread;			
void SDL_Lock_EventThread(void)
{
	if ( SDL_EventThread && (SDL_ThreadID() != event_thread) ) {
		
		SDL_mutexP(SDL_EventLock.lock);
		while ( ! SDL_EventLock.safe ) {
			SDL_Delay(1);
		}
	}
}
void SDL_Unlock_EventThread(void)
{
	if ( SDL_EventThread && (SDL_ThreadID() != event_thread) ) {
		SDL_mutexV(SDL_EventLock.lock);
	}
}
#ifdef __OS2__
#define INCL_DOSPROCESS
#include <os2.h>
#include <time.h>
#endif
static int SDLCALL SDL_GobbleEvents(void *unused)
{
	event_thread = SDL_ThreadID();
#ifdef __OS2__
#ifdef USE_DOSSETPRIORITY
	
	DosSetPriority(PRTYS_THREAD, PRTYC_REGULAR, +16, 0);
#endif
#endif
	while ( SDL_EventQ.active ) {
		SDL_VideoDevice *video = current_video;
		SDL_VideoDevice *this  = current_video;
		
		if ( video ) {
			video->PumpEvents(this);
		}
		
		SDL_CheckKeyRepeat();
#if !SDL_JOYSTICK_DISABLED
		
		if ( SDL_numjoysticks && (SDL_eventstate & SDL_JOYEVENTMASK) ) {
			SDL_JoystickUpdate();
		}
#endif
		
		SDL_EventLock.safe = 1;
		if ( SDL_timer_running ) {
			SDL_ThreadedTimerCheck();
		}
		SDL_Delay(1);
		
		SDL_mutexP(SDL_EventLock.lock);
		SDL_EventLock.safe = 0;
		SDL_mutexV(SDL_EventLock.lock);
	}
	SDL_SetTimerThreaded(0);
	event_thread = 0;
	return(0);
}
static int SDL_StartEventThread(Uint32 flags)
{
	
	SDL_EventThread = NULL;
	SDL_memset(&SDL_EventLock, 0, sizeof(SDL_EventLock));
	
#if !SDL_THREADS_DISABLED
	SDL_EventQ.lock = SDL_CreateMutex();
	if ( SDL_EventQ.lock == NULL ) {
#ifdef __MACOS__ 
		;
#else
		return(-1);
#endif
	}
#endif 
	SDL_EventQ.active = 1;
	if ( (flags&SDL_INIT_EVENTTHREAD) == SDL_INIT_EVENTTHREAD ) {
		SDL_EventLock.lock = SDL_CreateMutex();
		if ( SDL_EventLock.lock == NULL ) {
			return(-1);
		}
		SDL_EventLock.safe = 0;
		
		SDL_SetTimerThreaded(2);
#if (defined(__WIN32__) && !defined(_WIN32_WCE)) && !defined(HAVE_LIBC)
#undef SDL_CreateThread
		SDL_EventThread = SDL_CreateThread(SDL_GobbleEvents, NULL, NULL, NULL);
#else
		SDL_EventThread = SDL_CreateThread(SDL_GobbleEvents, NULL);
#endif
		if ( SDL_EventThread == NULL ) {
			return(-1);
		}
	} else {
		event_thread = 0;
	}
	return(0);
}
static void SDL_StopEventThread(void)
{
	SDL_EventQ.active = 0;
	if ( SDL_EventThread ) {
		SDL_WaitThread(SDL_EventThread, NULL);
		SDL_EventThread = NULL;
		SDL_DestroyMutex(SDL_EventLock.lock);
	}
#ifndef IPOD
	SDL_DestroyMutex(SDL_EventQ.lock);
#endif
}
Uint32 SDL_EventThreadID(void)
{
	return(event_thread);
}
void SDL_StopEventLoop(void)
{
	
	SDL_StopEventThread();
	
	SDL_AppActiveQuit();
	SDL_KeyboardQuit();
	SDL_MouseQuit();
	SDL_QuitQuit();
	
	SDL_EventQ.head = 0;
	SDL_EventQ.tail = 0;
	SDL_EventQ.wmmsg_next = 0;
}
int SDL_StartEventLoop(Uint32 flags)
{
	int retcode;
	
	SDL_EventThread = NULL;
	SDL_EventQ.lock = NULL;
	SDL_StopEventLoop();
	
	SDL_EventOK = NULL;
	SDL_memset(SDL_ProcessEvents,SDL_ENABLE,sizeof(SDL_ProcessEvents));
	SDL_eventstate = ~0;
	
	SDL_eventstate &= ~(0x00000001 << SDL_SYSWMEVENT);
	SDL_ProcessEvents[SDL_SYSWMEVENT] = SDL_IGNORE;
	
	retcode = 0;
	retcode += SDL_AppActiveInit();
	retcode += SDL_KeyboardInit();
	retcode += SDL_MouseInit();
	retcode += SDL_QuitInit();
	if ( retcode < 0 ) {
		
		return(-1);
	}
	
	if ( SDL_StartEventThread(flags) < 0 ) {
		SDL_StopEventLoop();
		return(-1);
	}
	return(0);
}
static int SDL_AddEvent(SDL_Event *event)
{
	int tail, added;
	tail = (SDL_EventQ.tail+1)%MAXEVENTS;
	if ( tail == SDL_EventQ.head ) {
		
		added = 0;
	} else {
		SDL_EventQ.event[SDL_EventQ.tail] = *event;
		if (event->type == SDL_SYSWMEVENT) {
			
			int next = SDL_EventQ.wmmsg_next;
			SDL_EventQ.wmmsg[next] = *event->syswm.msg;
		        SDL_EventQ.event[SDL_EventQ.tail].syswm.msg =
						&SDL_EventQ.wmmsg[next];
			SDL_EventQ.wmmsg_next = (next+1)%MAXEVENTS;
		}
		SDL_EventQ.tail = tail;
		added = 1;
	}
	return(added);
}
static int SDL_CutEvent(int spot)
{
	if ( spot == SDL_EventQ.head ) {
		SDL_EventQ.head = (SDL_EventQ.head+1)%MAXEVENTS;
		return(SDL_EventQ.head);
	} else
	if ( (spot+1)%MAXEVENTS == SDL_EventQ.tail ) {
		SDL_EventQ.tail = spot;
		return(SDL_EventQ.tail);
	} else
	
	{
		int here, next;
		
		if ( --SDL_EventQ.tail < 0 ) {
			SDL_EventQ.tail = MAXEVENTS-1;
		}
		for ( here=spot; here != SDL_EventQ.tail; here = next ) {
			next = (here+1)%MAXEVENTS;
			SDL_EventQ.event[here] = SDL_EventQ.event[next];
		}
		return(spot);
	}
	
}
int SDL_PeepEvents(SDL_Event *events, int numevents, SDL_eventaction action,
								Uint32 mask)
{
	int i, used;
	
	if ( ! SDL_EventQ.active ) {
		return(-1);
	}
	
	used = 0;
	if ( SDL_mutexP(SDL_EventQ.lock) == 0 ) {
		if ( action == SDL_ADDEVENT ) {
			for ( i=0; i<numevents; ++i ) {
				used += SDL_AddEvent(&events[i]);
			}
		} else {
			SDL_Event tmpevent;
			int spot;
			
			if ( events == NULL ) {
				action = SDL_PEEKEVENT;
				numevents = 1;
				events = &tmpevent;
			}
			spot = SDL_EventQ.head;
			while ((used < numevents)&&(spot != SDL_EventQ.tail)) {
				if ( mask & SDL_EVENTMASK(SDL_EventQ.event[spot].type) ) {
					events[used++] = SDL_EventQ.event[spot];
					if ( action == SDL_GETEVENT ) {
						spot = SDL_CutEvent(spot);
					} else {
						spot = (spot+1)%MAXEVENTS;
					}
				} else {
					spot = (spot+1)%MAXEVENTS;
				}
			}
		}
		SDL_mutexV(SDL_EventQ.lock);
	} else {
		SDL_SetError("Couldn't lock event queue");
		used = -1;
	}
	return(used);
}
void SDL_PumpEvents(void)
{
	if ( !SDL_EventThread ) {
		SDL_VideoDevice *video = current_video;
		SDL_VideoDevice *this  = current_video;
		
		if ( video ) {
			video->PumpEvents(this);
		}
		
		SDL_CheckKeyRepeat();
#if !SDL_JOYSTICK_DISABLED
		
		if ( SDL_numjoysticks && (SDL_eventstate & SDL_JOYEVENTMASK) ) {
			SDL_JoystickUpdate();
		}
#endif
	}
}
int SDL_PollEvent (SDL_Event *event)
{
	SDL_PumpEvents();
	
	if ( SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_ALLEVENTS) <= 0 )
		return 0;
	return 1;
}
int SDL_WaitEvent (SDL_Event *event)
{
	while ( 1 ) {
		SDL_PumpEvents();
		switch(SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_ALLEVENTS)) {
		    case -1: return 0;
		    case 1: return 1;
		    case 0: SDL_Delay(10);
		}
	}
}
int SDL_PushEvent(SDL_Event *event)
{
	if ( SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0) <= 0 )
		return -1;
	return 0;
}
void SDL_SetEventFilter (SDL_EventFilter filter)
{
	SDL_Event bitbucket;
	
	SDL_EventOK = filter;
	while ( SDL_PollEvent(&bitbucket) > 0 )
		;
}
SDL_EventFilter SDL_GetEventFilter(void)
{
	return(SDL_EventOK);
}
Uint8 SDL_EventState (Uint8 type, int state)
{
	SDL_Event bitbucket;
	Uint8 current_state;
	
	if ( type == 0xFF ) {
		current_state = SDL_IGNORE;
		for ( type=0; type<SDL_NUMEVENTS; ++type ) {
			if ( SDL_ProcessEvents[type] != SDL_IGNORE ) {
				current_state = SDL_ENABLE;
			}
			SDL_ProcessEvents[type] = state;
			if ( state == SDL_ENABLE ) {
				SDL_eventstate |= (0x00000001 << (type));
			} else {
				SDL_eventstate &= ~(0x00000001 << (type));
			}
		}
		while ( SDL_PollEvent(&bitbucket) > 0 )
			;
		return(current_state);
	}
	
	current_state = SDL_ProcessEvents[type];
	switch (state) {
		case SDL_IGNORE:
		case SDL_ENABLE:
			
			SDL_ProcessEvents[type] = state;
			if ( state == SDL_ENABLE ) {
				SDL_eventstate |= (0x00000001 << (type));
			} else {
				SDL_eventstate &= ~(0x00000001 << (type));
			}
			while ( SDL_PollEvent(&bitbucket) > 0 )
				;
			break;
		default:
			
			break;
	}
	return(current_state);
}
int SDL_PrivateSysWMEvent(SDL_SysWMmsg *message)
{
	int posted;
	posted = 0;
	if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
		SDL_Event event;
		SDL_memset(&event, 0, sizeof(event));
		event.type = SDL_SYSWMEVENT;
		event.syswm.msg = message;
		if ( (SDL_EventOK == NULL) || (*SDL_EventOK)(&event) ) {
			posted = 1;
			SDL_PushEvent(&event);
		}
	}
	
	return(posted);
}