src/events/SDL_events.c
author Ryan C. Gordon <icculus@icculus.org>
Thu, 08 Sep 2005 07:33:22 +0000
changeset 1140 af8b0f9ac2f4
parent 1123 28ac87a38c17
child 1190 173c063d4f55
permissions -rw-r--r--
iPod Linux framebuffer support.

--ryan.


Date: Sun, 19 Jun 2005 15:53:22 -0700
From: Joshua Oreman <oremanj@gmail.com>
To: sdl@libsdl.org
Subject: [SDL] [PATCH] iPod framebuffer video driver

Hi SDL-list,

I've been working on a port of SDL to iPodLinux
(http://www.ipodlinux.org). I've created a patch for both the
standard 2-bit iPod screen (using an unchangeable palette) and the
16-bit iPod photo. The patch is attached, against version 1.2.8.

I've created two pages on the iPodLinux wiki about this patch:
http://www.ipodlinux.org/Building_SDL and
http://www.ipodlinux.org/SDL_Programming. See those pages if you're
curious.

Comments? Questions? Is this something that might be able to get into SDL 1.2.9?

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