src/events/SDL_events.c
changeset 0 74212992fb08
child 252 e8157fcb3114
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/events/SDL_events.c	Thu Apr 26 16:45:43 2001 +0000
     1.3 @@ -0,0 +1,475 @@
     1.4 +/*
     1.5 +    SDL - Simple DirectMedia Layer
     1.6 +    Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
     1.7 +
     1.8 +    This library is free software; you can redistribute it and/or
     1.9 +    modify it under the terms of the GNU Library General Public
    1.10 +    License as published by the Free Software Foundation; either
    1.11 +    version 2 of the License, or (at your option) any later version.
    1.12 +
    1.13 +    This library is distributed in the hope that it will be useful,
    1.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    1.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    1.16 +    Library General Public License for more details.
    1.17 +
    1.18 +    You should have received a copy of the GNU Library General Public
    1.19 +    License along with this library; if not, write to the Free
    1.20 +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    1.21 +
    1.22 +    Sam Lantinga
    1.23 +    slouken@devolution.com
    1.24 +*/
    1.25 +
    1.26 +#ifdef SAVE_RCSID
    1.27 +static char rcsid =
    1.28 + "@(#) $Id$";
    1.29 +#endif
    1.30 +
    1.31 +/* General event handling code for SDL */
    1.32 +
    1.33 +#include <stdio.h>
    1.34 +#include <string.h>
    1.35 +
    1.36 +#include "SDL.h"
    1.37 +#include "SDL_thread.h"
    1.38 +#include "SDL_mutex.h"
    1.39 +#include "SDL_events.h"
    1.40 +#include "SDL_events_c.h"
    1.41 +#include "SDL_timer_c.h"
    1.42 +#ifndef DISABLE_JOYSTICK
    1.43 +#include "SDL_joystick_c.h"
    1.44 +#endif
    1.45 +#ifndef ENABLE_X11
    1.46 +#define DISABLE_X11
    1.47 +#endif
    1.48 +#include "SDL_syswm.h"
    1.49 +#include "SDL_sysevents.h"
    1.50 +
    1.51 +/* Public data -- the event filter */
    1.52 +SDL_EventFilter SDL_EventOK = NULL;
    1.53 +Uint8 SDL_ProcessEvents[SDL_NUMEVENTS];
    1.54 +static Uint32 SDL_eventstate = 0;
    1.55 +
    1.56 +/* Private data -- event queue */
    1.57 +#define MAXEVENTS	128
    1.58 +static struct {
    1.59 +	SDL_mutex *lock;
    1.60 +	int active;
    1.61 +	int head;
    1.62 +	int tail;
    1.63 +	SDL_Event event[MAXEVENTS];
    1.64 +	int wmmsg_next;
    1.65 +	struct SDL_SysWMmsg wmmsg[MAXEVENTS];
    1.66 +} SDL_EventQ;
    1.67 +
    1.68 +/* Private data -- event locking structure */
    1.69 +static struct {
    1.70 +	SDL_mutex *lock;
    1.71 +	int safe;
    1.72 +} SDL_EventLock;
    1.73 +
    1.74 +/* Thread functions */
    1.75 +static SDL_Thread *SDL_EventThread = NULL;	/* Thread handle */
    1.76 +static Uint32 event_thread;			/* The event thread id */
    1.77 +
    1.78 +void SDL_Lock_EventThread(void)
    1.79 +{
    1.80 +	if ( SDL_EventThread && (SDL_ThreadID() != event_thread) ) {
    1.81 +		/* Grab lock and spin until we're sure event thread stopped */
    1.82 +		SDL_mutexP(SDL_EventLock.lock);
    1.83 +		while ( ! SDL_EventLock.safe ) {
    1.84 +			SDL_Delay(1);
    1.85 +		}
    1.86 +	}
    1.87 +}
    1.88 +void SDL_Unlock_EventThread(void)
    1.89 +{
    1.90 +	if ( SDL_EventThread && (SDL_ThreadID() != event_thread) ) {
    1.91 +		SDL_mutexV(SDL_EventLock.lock);
    1.92 +	}
    1.93 +}
    1.94 +
    1.95 +static int SDL_GobbleEvents(void *unused)
    1.96 +{
    1.97 +	SDL_SetTimerThreaded(2);
    1.98 +	event_thread = SDL_ThreadID();
    1.99 +	while ( SDL_EventQ.active ) {
   1.100 +		SDL_VideoDevice *video = current_video;
   1.101 +		SDL_VideoDevice *this  = current_video;
   1.102 +
   1.103 +		/* Get events from the video subsystem */
   1.104 +		if ( video ) {
   1.105 +			video->PumpEvents(this);
   1.106 +		}
   1.107 +
   1.108 +		/* Queue pending key-repeat events */
   1.109 +		SDL_CheckKeyRepeat();
   1.110 +
   1.111 +#ifndef DISABLE_JOYSTICK
   1.112 +		/* Check for joystick state change */
   1.113 +		if ( SDL_numjoysticks && (SDL_eventstate & SDL_JOYEVENTMASK) ) {
   1.114 +			SDL_JoystickUpdate();
   1.115 +		}
   1.116 +#endif
   1.117 +
   1.118 +		/* Give up the CPU for the rest of our timeslice */
   1.119 +		SDL_EventLock.safe = 1;
   1.120 +		if( SDL_timer_running ) {
   1.121 +			SDL_ThreadedTimerCheck();
   1.122 +		}
   1.123 +		SDL_Delay(1);
   1.124 +
   1.125 +		/* Check for event locking.
   1.126 +		   On the P of the lock mutex, if the lock is held, this thread
   1.127 +		   will wait until the lock is released before continuing.  The
   1.128 +		   safe flag will be set, meaning that the other thread can go
   1.129 +		   about it's business.  The safe flag is reset before the V,
   1.130 +		   so as soon as the mutex is free, other threads can see that
   1.131 +		   it's not safe to interfere with the event thread.
   1.132 +		 */
   1.133 +		SDL_mutexP(SDL_EventLock.lock);
   1.134 +		SDL_EventLock.safe = 0;
   1.135 +		SDL_mutexV(SDL_EventLock.lock);
   1.136 +	}
   1.137 +	SDL_SetTimerThreaded(0);
   1.138 +	event_thread = 0;
   1.139 +	return(0);
   1.140 +}
   1.141 +
   1.142 +static int SDL_StartEventThread(Uint32 flags)
   1.143 +{
   1.144 +	/* Reset everything to zero */
   1.145 +	SDL_EventThread = NULL;
   1.146 +	memset(&SDL_EventLock, 0, sizeof(SDL_EventLock));
   1.147 +
   1.148 +	/* Create the lock and set ourselves active */
   1.149 +#ifndef DISABLE_THREADS
   1.150 +	SDL_EventQ.lock = SDL_CreateMutex();
   1.151 +	if ( SDL_EventQ.lock == NULL ) {
   1.152 +#ifdef macintosh /* On MacOS 7/8, you can't multithread, so no lock needed */
   1.153 +		;
   1.154 +#else
   1.155 +		return(-1);
   1.156 +#endif
   1.157 +	}
   1.158 +#endif /* !DISABLE_THREADS */
   1.159 +	SDL_EventQ.active = 1;
   1.160 +
   1.161 +	if ( (flags&SDL_INIT_EVENTTHREAD) == SDL_INIT_EVENTTHREAD ) {
   1.162 +		SDL_EventLock.lock = SDL_CreateMutex();
   1.163 +		if ( SDL_EventLock.lock == NULL ) {
   1.164 +			return(-1);
   1.165 +		}
   1.166 +		SDL_EventLock.safe = 0;
   1.167 +
   1.168 +		SDL_EventThread = SDL_CreateThread(SDL_GobbleEvents, NULL);
   1.169 +		if ( SDL_EventThread == NULL ) {
   1.170 +			return(-1);
   1.171 +		}
   1.172 +	} else {
   1.173 +		event_thread = 0;
   1.174 +	}
   1.175 +	return(0);
   1.176 +}
   1.177 +
   1.178 +static void SDL_StopEventThread(void)
   1.179 +{
   1.180 +	SDL_EventQ.active = 0;
   1.181 +	if ( SDL_EventThread ) {
   1.182 +		SDL_WaitThread(SDL_EventThread, NULL);
   1.183 +		SDL_EventThread = NULL;
   1.184 +		SDL_DestroyMutex(SDL_EventLock.lock);
   1.185 +	}
   1.186 +	SDL_DestroyMutex(SDL_EventQ.lock);
   1.187 +}
   1.188 +
   1.189 +Uint32 SDL_EventThreadID(void)
   1.190 +{
   1.191 +	return(event_thread);
   1.192 +}
   1.193 +
   1.194 +/* Public functions */
   1.195 +
   1.196 +void SDL_StopEventLoop(void)
   1.197 +{
   1.198 +	/* Halt the event thread, if running */
   1.199 +	SDL_StopEventThread();
   1.200 +
   1.201 +	/* Clean out EventQ */
   1.202 +	SDL_EventQ.head = 0;
   1.203 +	SDL_EventQ.tail = 0;
   1.204 +	SDL_EventQ.wmmsg_next = 0;
   1.205 +}
   1.206 +
   1.207 +/* This function (and associated calls) may be called more than once */
   1.208 +int SDL_StartEventLoop(Uint32 flags)
   1.209 +{
   1.210 +	int retcode;
   1.211 +
   1.212 +	/* Clean out the event queue */
   1.213 +	SDL_EventThread = NULL;
   1.214 +	SDL_EventQ.lock = NULL;
   1.215 +	SDL_StopEventLoop();
   1.216 +
   1.217 +	/* No filter to start with, process most event types */
   1.218 +	SDL_EventOK = NULL;
   1.219 +	memset(SDL_ProcessEvents,SDL_ENABLE,sizeof(SDL_ProcessEvents));
   1.220 +	SDL_eventstate = ~0;
   1.221 +	/* It's not save to call SDL_EventState() yet */
   1.222 +	SDL_eventstate &= ~(0x00000001 << SDL_SYSWMEVENT);
   1.223 +	SDL_ProcessEvents[SDL_SYSWMEVENT] = SDL_IGNORE;
   1.224 +
   1.225 +	/* Initialize event handlers */
   1.226 +	retcode = 0;
   1.227 +	retcode += SDL_AppActiveInit();
   1.228 +	retcode += SDL_KeyboardInit();
   1.229 +	retcode += SDL_MouseInit();
   1.230 +	retcode += SDL_QuitInit();
   1.231 +	if ( retcode < 0 ) {
   1.232 +		/* We don't expect them to fail, but... */
   1.233 +		return(-1);
   1.234 +	}
   1.235 +
   1.236 +	/* Create the lock and event thread */
   1.237 +	if ( SDL_StartEventThread(flags) < 0 ) {
   1.238 +		SDL_StopEventLoop();
   1.239 +		return(-1);
   1.240 +	}
   1.241 +	return(0);
   1.242 +}
   1.243 +
   1.244 +
   1.245 +/* Add an event to the event queue -- called with the queue locked */
   1.246 +static int SDL_AddEvent(SDL_Event *event)
   1.247 +{
   1.248 +	int tail, added;
   1.249 +
   1.250 +	tail = (SDL_EventQ.tail+1)%MAXEVENTS;
   1.251 +	if ( tail == SDL_EventQ.head ) {
   1.252 +		/* Overflow, drop event */
   1.253 +		added = 0;
   1.254 +	} else {
   1.255 +		SDL_EventQ.event[SDL_EventQ.tail] = *event;
   1.256 +		if (event->type == SDL_SYSWMEVENT) {
   1.257 +			/* Note that it's possible to lose an event */
   1.258 +			int next = SDL_EventQ.wmmsg_next;
   1.259 +			SDL_EventQ.wmmsg[next] = *event->syswm.msg;
   1.260 +		        SDL_EventQ.event[SDL_EventQ.tail].syswm.msg =
   1.261 +						&SDL_EventQ.wmmsg[next];
   1.262 +			SDL_EventQ.wmmsg_next = (next+1)%MAXEVENTS;
   1.263 +		}
   1.264 +		SDL_EventQ.tail = tail;
   1.265 +		added = 1;
   1.266 +	}
   1.267 +	return(added);
   1.268 +}
   1.269 +
   1.270 +/* Cut an event, and return the next valid spot, or the tail */
   1.271 +/*                           -- called with the queue locked */
   1.272 +static int SDL_CutEvent(int spot)
   1.273 +{
   1.274 +	if ( spot == SDL_EventQ.head ) {
   1.275 +		SDL_EventQ.head = (SDL_EventQ.head+1)%MAXEVENTS;
   1.276 +		return(SDL_EventQ.head);
   1.277 +	} else
   1.278 +	if ( (spot+1)%MAXEVENTS == SDL_EventQ.tail ) {
   1.279 +		SDL_EventQ.tail = spot;
   1.280 +		return(SDL_EventQ.tail);
   1.281 +	} else
   1.282 +	/* We cut the middle -- shift everything over */
   1.283 +	{
   1.284 +		int here, next;
   1.285 +
   1.286 +		/* This can probably be optimized with memcpy() -- careful! */
   1.287 +		if ( --SDL_EventQ.tail < 0 ) {
   1.288 +			SDL_EventQ.tail = MAXEVENTS-1;
   1.289 +		}
   1.290 +		for ( here=spot; here != SDL_EventQ.tail; here = next ) {
   1.291 +			next = (here+1)%MAXEVENTS;
   1.292 +			SDL_EventQ.event[here] = SDL_EventQ.event[next];
   1.293 +		}
   1.294 +		return(spot);
   1.295 +	}
   1.296 +	/* NOTREACHED */
   1.297 +}
   1.298 +
   1.299 +/* Lock the event queue, take a peep at it, and unlock it */
   1.300 +int SDL_PeepEvents(SDL_Event *events, int numevents, SDL_eventaction action,
   1.301 +								Uint32 mask)
   1.302 +{
   1.303 +	int i, used;
   1.304 +
   1.305 +	/* Don't look after we've quit */
   1.306 +	if ( ! SDL_EventQ.active ) {
   1.307 +		return(0);
   1.308 +	}
   1.309 +	/* Lock the event queue */
   1.310 +	used = 0;
   1.311 +	if ( SDL_mutexP(SDL_EventQ.lock) == 0 ) {
   1.312 +		if ( action == SDL_ADDEVENT ) {
   1.313 +			for ( i=0; i<numevents; ++i ) {
   1.314 +				used += SDL_AddEvent(&events[i]);
   1.315 +			}
   1.316 +		} else {
   1.317 +			SDL_Event tmpevent;
   1.318 +			int spot;
   1.319 +
   1.320 +			/* If 'events' is NULL, just see if they exist */
   1.321 +			if ( events == NULL ) {
   1.322 +				action = SDL_PEEKEVENT;
   1.323 +				numevents = 1;
   1.324 +				events = &tmpevent;
   1.325 +			}
   1.326 +			spot = SDL_EventQ.head;
   1.327 +			while ((used < numevents)&&(spot != SDL_EventQ.tail)) {
   1.328 +				if ( mask & SDL_EVENTMASK(SDL_EventQ.event[spot].type) ) {
   1.329 +					events[used++] = SDL_EventQ.event[spot];
   1.330 +					if ( action == SDL_GETEVENT ) {
   1.331 +						spot = SDL_CutEvent(spot);
   1.332 +					} else {
   1.333 +						spot = (spot+1)%MAXEVENTS;
   1.334 +					}
   1.335 +				} else {
   1.336 +					spot = (spot+1)%MAXEVENTS;
   1.337 +				}
   1.338 +			}
   1.339 +		}
   1.340 +		SDL_mutexV(SDL_EventQ.lock);
   1.341 +	} else {
   1.342 +		SDL_SetError("Couldn't lock event queue");
   1.343 +		used = -1;
   1.344 +	}
   1.345 +	return(used);
   1.346 +}
   1.347 +
   1.348 +/* Run the system dependent event loops */
   1.349 +void SDL_PumpEvents(void)
   1.350 +{
   1.351 +	if ( !SDL_EventThread ) {
   1.352 +		SDL_VideoDevice *video = current_video;
   1.353 +		SDL_VideoDevice *this  = current_video;
   1.354 +
   1.355 +		/* Get events from the video subsystem */
   1.356 +		if ( video ) {
   1.357 +			video->PumpEvents(this);
   1.358 +		}
   1.359 +
   1.360 +		/* Queue pending key-repeat events */
   1.361 +		SDL_CheckKeyRepeat();
   1.362 +
   1.363 +#ifndef DISABLE_JOYSTICK
   1.364 +		/* Check for joystick state change */
   1.365 +		if ( SDL_numjoysticks && (SDL_eventstate & SDL_JOYEVENTMASK) ) {
   1.366 +			SDL_JoystickUpdate();
   1.367 +		}
   1.368 +#endif
   1.369 +	}
   1.370 +}
   1.371 +
   1.372 +/* Public functions */
   1.373 +
   1.374 +int SDL_PollEvent (SDL_Event *event)
   1.375 +{
   1.376 +	SDL_PumpEvents();
   1.377 +
   1.378 +	return(SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_ALLEVENTS));
   1.379 +}
   1.380 +
   1.381 +int SDL_WaitEvent (SDL_Event *event)
   1.382 +{
   1.383 +	while ( 1 ) {
   1.384 +		SDL_PumpEvents();
   1.385 +		switch(SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_ALLEVENTS)) {
   1.386 +		    case -1: return -1; 
   1.387 +		    case 1: return 1;
   1.388 +		    case 0: SDL_Delay(10);
   1.389 +		}
   1.390 +	}
   1.391 +}
   1.392 +
   1.393 +int SDL_PushEvent(SDL_Event *event)
   1.394 +{
   1.395 +	return(SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0));
   1.396 +}
   1.397 +
   1.398 +void SDL_SetEventFilter (SDL_EventFilter filter)
   1.399 +{
   1.400 +	SDL_Event bitbucket;
   1.401 +
   1.402 +	/* Set filter and discard pending events */
   1.403 +	SDL_EventOK = filter;
   1.404 +	while ( SDL_PollEvent(&bitbucket) > 0 )
   1.405 +		;
   1.406 +}
   1.407 +
   1.408 +SDL_EventFilter SDL_GetEventFilter(void)
   1.409 +{
   1.410 +	return(SDL_EventOK);
   1.411 +}
   1.412 +
   1.413 +Uint8 SDL_EventState (Uint8 type, int state)
   1.414 +{
   1.415 +	SDL_Event bitbucket;
   1.416 +	Uint8 current_state;
   1.417 +
   1.418 +	/* If SDL_ALLEVENTS was specified... */
   1.419 +	if ( type == 0xFF ) {
   1.420 +		current_state = SDL_IGNORE;
   1.421 +		for ( type=0; type<SDL_NUMEVENTS; ++type ) {
   1.422 +			if ( SDL_ProcessEvents[type] != SDL_IGNORE ) {
   1.423 +				current_state = SDL_ENABLE;
   1.424 +			}
   1.425 +			SDL_ProcessEvents[type] = state;
   1.426 +			if ( state == SDL_ENABLE ) {
   1.427 +				SDL_eventstate |= (0x00000001 << (type));
   1.428 +			} else {
   1.429 +				SDL_eventstate &= ~(0x00000001 << (type));
   1.430 +			}
   1.431 +		}
   1.432 +		while ( SDL_PollEvent(&bitbucket) > 0 )
   1.433 +			;
   1.434 +		return(current_state);
   1.435 +	}
   1.436 +
   1.437 +	/* Just set the state for one event type */
   1.438 +	current_state = SDL_ProcessEvents[type];
   1.439 +	switch (state) {
   1.440 +		case SDL_IGNORE:
   1.441 +		case SDL_ENABLE:
   1.442 +			/* Set state and discard pending events */
   1.443 +			SDL_ProcessEvents[type] = state;
   1.444 +			if ( state == SDL_ENABLE ) {
   1.445 +				SDL_eventstate |= (0x00000001 << (type));
   1.446 +			} else {
   1.447 +				SDL_eventstate &= ~(0x00000001 << (type));
   1.448 +			}
   1.449 +			while ( SDL_PollEvent(&bitbucket) > 0 )
   1.450 +				;
   1.451 +			break;
   1.452 +		default:
   1.453 +			/* Querying state? */
   1.454 +			break;
   1.455 +	}
   1.456 +	return(current_state);
   1.457 +}
   1.458 +
   1.459 +/* This is a generic event handler.
   1.460 + */
   1.461 +int SDL_PrivateSysWMEvent(SDL_SysWMmsg *message)
   1.462 +{
   1.463 +	int posted;
   1.464 +
   1.465 +	posted = 0;
   1.466 +	if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
   1.467 +		SDL_Event event;
   1.468 +		memset(&event, 0, sizeof(event));
   1.469 +		event.type = SDL_SYSWMEVENT;
   1.470 +		event.syswm.msg = message;
   1.471 +		if ( (SDL_EventOK == NULL) || (*SDL_EventOK)(&event) ) {
   1.472 +			posted = 1;
   1.473 +			SDL_PushEvent(&event);
   1.474 +		}
   1.475 +	}
   1.476 +	/* Update internal event state */
   1.477 +	return(posted);
   1.478 +}