Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
5131 clevermous 1
/*
2
    SDL - Simple DirectMedia Layer
3
    Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
4
 
5
    This library is free software; you can redistribute it and/or
6
    modify it under the terms of the GNU Library General Public
7
    License as published by the Free Software Foundation; either
8
    version 2 of the License, or (at your option) any later version.
9
 
10
    This library is distributed in the hope that it will be useful,
11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13
    Library General Public License for more details.
14
 
15
    You should have received a copy of the GNU Library General Public
16
    License along with this library; if not, write to the Free
17
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
 
19
    Sam Lantinga
20
    slouken@devolution.com
21
*/
22
 
23
 
24
/* General event handling code for SDL */
25
 
26
#include 
27
#include 
28
 
29
#include "SDL.h"
30
#include "SDL_thread.h"
31
#include "SDL_mutex.h"
32
#include "SDL_events.h"
33
#include "SDL_events_c.h"
34
#include "SDL_timer_c.h"
35
#ifndef DISABLE_JOYSTICK
36
#include "SDL_joystick_c.h"
37
#endif
38
#ifndef ENABLE_X11
39
#define DISABLE_X11
40
#endif
41
#include "SDL_syswm.h"
42
#include "SDL_sysevents.h"
43
 
44
/* Public data -- the event filter */
45
SDL_EventFilter SDL_EventOK = NULL;
46
Uint8 SDL_ProcessEvents[SDL_NUMEVENTS];
47
static Uint32 SDL_eventstate = 0;
48
 
49
/* Private data -- event queue */
50
#define MAXEVENTS	128
51
static struct {
52
	SDL_mutex *lock;
53
	int active;
54
	int head;
55
	int tail;
56
	SDL_Event event[MAXEVENTS];
57
	int wmmsg_next;
58
	struct SDL_SysWMmsg wmmsg[MAXEVENTS];
59
} SDL_EventQ;
60
 
61
/* Private data -- event locking structure */
62
static struct {
63
	SDL_mutex *lock;
64
	int safe;
65
} SDL_EventLock;
66
 
67
/* Thread functions */
68
static SDL_Thread *SDL_EventThread = NULL;	/* Thread handle */
69
static Uint32 event_thread;			/* The event thread id */
70
 
71
void SDL_Lock_EventThread(void)
72
{
73
	if ( SDL_EventThread && (SDL_ThreadID() != event_thread) ) {
74
		/* Grab lock and spin until we're sure event thread stopped */
75
		SDL_mutexP(SDL_EventLock.lock);
76
		while ( ! SDL_EventLock.safe ) {
77
			SDL_Delay(1);
78
		}
79
	}
80
}
81
void SDL_Unlock_EventThread(void)
82
{
83
	if ( SDL_EventThread && (SDL_ThreadID() != event_thread) ) {
84
		SDL_mutexV(SDL_EventLock.lock);
85
	}
86
}
87
 
88
static int SDL_GobbleEvents(void *unused)
89
{
90
	SDL_SetTimerThreaded(2);
91
	event_thread = SDL_ThreadID();
92
	while ( SDL_EventQ.active ) {
93
		SDL_VideoDevice *video = current_video;
94
		SDL_VideoDevice *this  = current_video;
95
 
96
		/* Get events from the video subsystem */
97
		if ( video ) {
98
			video->PumpEvents(this);
99
		}
100
 
101
		/* Queue pending key-repeat events */
102
		SDL_CheckKeyRepeat();
103
 
104
#ifndef DISABLE_JOYSTICK
105
		/* Check for joystick state change */
106
		if ( SDL_numjoysticks && (SDL_eventstate & SDL_JOYEVENTMASK) ) {
107
			SDL_JoystickUpdate();
108
		}
109
#endif
110
 
111
		/* Give up the CPU for the rest of our timeslice */
112
		SDL_EventLock.safe = 1;
113
		if( SDL_timer_running ) {
114
			SDL_ThreadedTimerCheck();
115
		}
116
		SDL_Delay(1);
117
 
118
		/* Check for event locking.
119
		   On the P of the lock mutex, if the lock is held, this thread
120
		   will wait until the lock is released before continuing.  The
121
		   safe flag will be set, meaning that the other thread can go
122
		   about it's business.  The safe flag is reset before the V,
123
		   so as soon as the mutex is free, other threads can see that
124
		   it's not safe to interfere with the event thread.
125
		 */
126
		SDL_mutexP(SDL_EventLock.lock);
127
		SDL_EventLock.safe = 0;
128
		SDL_mutexV(SDL_EventLock.lock);
129
	}
130
	SDL_SetTimerThreaded(0);
131
	event_thread = 0;
132
	return(0);
133
}
134
 
135
static int SDL_StartEventThread(Uint32 flags)
136
{
137
	/* Reset everything to zero */
138
	SDL_EventThread = NULL;
139
	memset(&SDL_EventLock, 0, sizeof(SDL_EventLock));
140
 
141
	/* Create the lock and set ourselves active */
142
#ifndef DISABLE_THREADS
143
	SDL_EventQ.lock = SDL_CreateMutex();
144
	if ( SDL_EventQ.lock == NULL ) {
145
#ifdef macintosh /* On MacOS 7/8, you can't multithread, so no lock needed */
146
		;
147
#else
148
		return(-1);
149
#endif
150
	}
151
#endif /* !DISABLE_THREADS */
152
	SDL_EventQ.active = 1;
153
 
154
	if ( (flags&SDL_INIT_EVENTTHREAD) == SDL_INIT_EVENTTHREAD ) {
155
		SDL_EventLock.lock = SDL_CreateMutex();
156
		if ( SDL_EventLock.lock == NULL ) {
157
			return(-1);
158
		}
159
		SDL_EventLock.safe = 0;
160
 
161
		SDL_EventThread = SDL_CreateThread(SDL_GobbleEvents, NULL);
162
		if ( SDL_EventThread == NULL ) {
163
			return(-1);
164
		}
165
	} else {
166
		event_thread = 0;
167
	}
168
	return(0);
169
}
170
 
171
static void SDL_StopEventThread(void)
172
{
173
	SDL_EventQ.active = 0;
174
	if ( SDL_EventThread ) {
175
		SDL_WaitThread(SDL_EventThread, NULL);
176
		SDL_EventThread = NULL;
177
		SDL_DestroyMutex(SDL_EventLock.lock);
178
	}
179
	SDL_DestroyMutex(SDL_EventQ.lock);
180
}
181
 
182
Uint32 SDL_EventThreadID(void)
183
{
184
	return(event_thread);
185
}
186
 
187
/* Public functions */
188
 
189
void SDL_StopEventLoop(void)
190
{
191
	/* Halt the event thread, if running */
192
	SDL_StopEventThread();
193
 
194
	/* Clean out EventQ */
195
	SDL_EventQ.head = 0;
196
	SDL_EventQ.tail = 0;
197
	SDL_EventQ.wmmsg_next = 0;
198
}
199
 
200
/* This function (and associated calls) may be called more than once */
201
int SDL_StartEventLoop(Uint32 flags)
202
{
203
	int retcode;
204
 
205
	/* Clean out the event queue */
206
	SDL_EventThread = NULL;
207
	SDL_EventQ.lock = NULL;
208
	SDL_StopEventLoop();
209
 
210
	/* No filter to start with, process most event types */
211
	SDL_EventOK = NULL;
212
	memset(SDL_ProcessEvents,SDL_ENABLE,sizeof(SDL_ProcessEvents));
213
	SDL_eventstate = ~0;
214
	/* It's not save to call SDL_EventState() yet */
215
	SDL_eventstate &= ~(0x00000001 << SDL_SYSWMEVENT);
216
	SDL_ProcessEvents[SDL_SYSWMEVENT] = SDL_IGNORE;
217
 
218
	/* Initialize event handlers */
219
	retcode = 0;
220
	retcode += SDL_AppActiveInit();
221
	retcode += SDL_KeyboardInit();
222
	retcode += SDL_MouseInit();
223
	retcode += SDL_QuitInit();
224
	if ( retcode < 0 ) {
225
		/* We don't expect them to fail, but... */
226
		return(-1);
227
	}
228
 
229
	/* Create the lock and event thread */
230
	if ( SDL_StartEventThread(flags) < 0 ) {
231
		SDL_StopEventLoop();
232
		return(-1);
233
	}
234
	return(0);
235
}
236
 
237
 
238
/* Add an event to the event queue -- called with the queue locked */
239
static int SDL_AddEvent(SDL_Event *event)
240
{
241
	int tail, added;
242
 
243
	tail = (SDL_EventQ.tail+1)%MAXEVENTS;
244
	if ( tail == SDL_EventQ.head ) {
245
		/* Overflow, drop event */
246
		added = 0;
247
	} else {
248
		SDL_EventQ.event[SDL_EventQ.tail] = *event;
249
		if (event->type == SDL_SYSWMEVENT) {
250
			/* Note that it's possible to lose an event */
251
			int next = SDL_EventQ.wmmsg_next;
252
			SDL_EventQ.wmmsg[next] = *event->syswm.msg;
253
		        SDL_EventQ.event[SDL_EventQ.tail].syswm.msg =
254
						&SDL_EventQ.wmmsg[next];
255
			SDL_EventQ.wmmsg_next = (next+1)%MAXEVENTS;
256
		}
257
		SDL_EventQ.tail = tail;
258
		added = 1;
259
	}
260
	return(added);
261
}
262
 
263
/* Cut an event, and return the next valid spot, or the tail */
264
/*                           -- called with the queue locked */
265
static int SDL_CutEvent(int spot)
266
{
267
	if ( spot == SDL_EventQ.head ) {
268
		SDL_EventQ.head = (SDL_EventQ.head+1)%MAXEVENTS;
269
		return(SDL_EventQ.head);
270
	} else
271
	if ( (spot+1)%MAXEVENTS == SDL_EventQ.tail ) {
272
		SDL_EventQ.tail = spot;
273
		return(SDL_EventQ.tail);
274
	} else
275
	/* We cut the middle -- shift everything over */
276
	{
277
		int here, next;
278
 
279
		/* This can probably be optimized with memcpy() -- careful! */
280
		if ( --SDL_EventQ.tail < 0 ) {
281
			SDL_EventQ.tail = MAXEVENTS-1;
282
		}
283
		for ( here=spot; here != SDL_EventQ.tail; here = next ) {
284
			next = (here+1)%MAXEVENTS;
285
			SDL_EventQ.event[here] = SDL_EventQ.event[next];
286
		}
287
		return(spot);
288
	}
289
	/* NOTREACHED */
290
}
291
 
292
/* Lock the event queue, take a peep at it, and unlock it */
293
int SDL_PeepEvents(SDL_Event *events, int numevents, SDL_eventaction action,
294
								Uint32 mask)
295
{
296
	int i, used;
297
 
298
	/* Don't look after we've quit */
299
	if ( ! SDL_EventQ.active ) {
300
		return(0);
301
	}
302
	/* Lock the event queue */
303
	used = 0;
304
	if ( SDL_mutexP(SDL_EventQ.lock) == 0 ) {
305
		if ( action == SDL_ADDEVENT ) {
306
			for ( i=0; i
307
				used += SDL_AddEvent(&events[i]);
308
			}
309
		} else {
310
			SDL_Event tmpevent;
311
			int spot;
312
 
313
			/* If 'events' is NULL, just see if they exist */
314
			if ( events == NULL ) {
315
				action = SDL_PEEKEVENT;
316
				numevents = 1;
317
				events = &tmpevent;
318
			}
319
			spot = SDL_EventQ.head;
320
			while ((used < numevents)&&(spot != SDL_EventQ.tail)) {
321
				if ( mask & SDL_EVENTMASK(SDL_EventQ.event[spot].type) ) {
322
					events[used++] = SDL_EventQ.event[spot];
323
					if ( action == SDL_GETEVENT ) {
324
						spot = SDL_CutEvent(spot);
325
					} else {
326
						spot = (spot+1)%MAXEVENTS;
327
					}
328
				} else {
329
					spot = (spot+1)%MAXEVENTS;
330
				}
331
			}
332
		}
333
		SDL_mutexV(SDL_EventQ.lock);
334
	} else {
335
		SDL_SetError("Couldn't lock event queue");
336
		used = -1;
337
	}
338
	return(used);
339
}
340
 
341
/* Run the system dependent event loops */
342
void SDL_PumpEvents(void)
343
{
344
	if ( !SDL_EventThread ) {
345
		SDL_VideoDevice *video = current_video;
346
		SDL_VideoDevice *this  = current_video;
347
 
348
		/* Get events from the video subsystem */
349
		if ( video ) {
350
			video->PumpEvents(this);
351
		}
352
 
353
		/* Queue pending key-repeat events */
354
		SDL_CheckKeyRepeat();
355
 
356
#ifndef DISABLE_JOYSTICK
357
		/* Check for joystick state change */
358
		if ( SDL_numjoysticks && (SDL_eventstate & SDL_JOYEVENTMASK) ) {
359
			SDL_JoystickUpdate();
360
		}
361
#endif
362
	}
363
}
364
 
365
/* Public functions */
366
 
367
int SDL_PollEvent (SDL_Event *event)
368
{
369
	SDL_PumpEvents();
370
 
371
	return(SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_ALLEVENTS));
372
}
373
 
374
int SDL_WaitEvent (SDL_Event *event)
375
{
376
	while ( 1 ) {
377
		SDL_PumpEvents();
378
		switch(SDL_PeepEvents(event, 1, SDL_GETEVENT, SDL_ALLEVENTS)) {
379
		    case -1: return -1;
380
		    case 1: return 1;
381
		    case 0: SDL_Delay(10);
382
		}
383
	}
384
}
385
 
386
int SDL_PushEvent(SDL_Event *event)
387
{
388
	return(SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0));
389
}
390
 
391
void SDL_SetEventFilter (SDL_EventFilter filter)
392
{
393
	SDL_Event bitbucket;
394
 
395
	/* Set filter and discard pending events */
396
	SDL_EventOK = filter;
397
	while ( SDL_PollEvent(&bitbucket) > 0 )
398
		;
399
}
400
 
401
SDL_EventFilter SDL_GetEventFilter(void)
402
{
403
	return(SDL_EventOK);
404
}
405
 
406
Uint8 SDL_EventState (Uint8 type, int state)
407
{
408
	SDL_Event bitbucket;
409
	Uint8 current_state;
410
 
411
	/* If SDL_ALLEVENTS was specified... */
412
	if ( type == 0xFF ) {
413
		current_state = SDL_IGNORE;
414
		for ( type=0; type
415
			if ( SDL_ProcessEvents[type] != SDL_IGNORE ) {
416
				current_state = SDL_ENABLE;
417
			}
418
			SDL_ProcessEvents[type] = state;
419
			if ( state == SDL_ENABLE ) {
420
				SDL_eventstate |= (0x00000001 << (type));
421
			} else {
422
				SDL_eventstate &= ~(0x00000001 << (type));
423
			}
424
		}
425
		while ( SDL_PollEvent(&bitbucket) > 0 )
426
			;
427
		return(current_state);
428
	}
429
 
430
	/* Just set the state for one event type */
431
	current_state = SDL_ProcessEvents[type];
432
	switch (state) {
433
		case SDL_IGNORE:
434
		case SDL_ENABLE:
435
			/* Set state and discard pending events */
436
			SDL_ProcessEvents[type] = state;
437
			if ( state == SDL_ENABLE ) {
438
				SDL_eventstate |= (0x00000001 << (type));
439
			} else {
440
				SDL_eventstate &= ~(0x00000001 << (type));
441
			}
442
			while ( SDL_PollEvent(&bitbucket) > 0 )
443
				;
444
			break;
445
		default:
446
			/* Querying state? */
447
			break;
448
	}
449
	return(current_state);
450
}
451
 
452
/* This is a generic event handler.
453
 */
454
int SDL_PrivateSysWMEvent(SDL_SysWMmsg *message)
455
{
456
	int posted;
457
 
458
	posted = 0;
459
	if ( SDL_ProcessEvents[SDL_SYSWMEVENT] == SDL_ENABLE ) {
460
		SDL_Event event;
461
		memset(&event, 0, sizeof(event));
462
		event.type = SDL_SYSWMEVENT;
463
		event.syswm.msg = message;
464
		if ( (SDL_EventOK == NULL) || (*SDL_EventOK)(&event) ) {
465
			posted = 1;
466
			SDL_PushEvent(&event);
467
		}
468
	}
469
	/* Update internal event state */
470
	return(posted);
471
}