Merged Jim's Google Summer of Code work from SDL-gsoc2010_gesture
authorSam Lantinga <slouken@libsdl.org>
Sun, 22 Aug 2010 12:07:55 -0700
changeset 4694 c24ba2cc9583
parent 4638 08d22c54a21f (current diff)
parent 4693 2ede56a19f2f (diff)
child 4729 1f7ad083fd3c
Merged Jim's Google Summer of Code work from SDL-gsoc2010_gesture
configure.in
include/SDL_events.h
src/video/cocoa/SDL_cocoakeyboard.m
src/video/uikit/SDL_uikitview.m
src/video/win32/SDL_win32events.c
src/video/win32/SDL_win32video.h
src/video/win32/SDL_win32window.c
src/video/x11/SDL_x11events.c
src/video/x11/SDL_x11video.c
src/video/x11/SDL_x11video.h
--- a/.hgignore	Sun Aug 22 11:56:07 2010 -0700
+++ b/.hgignore	Sun Aug 22 12:07:55 2010 -0700
@@ -90,5 +90,6 @@
 test/testatomic
 test/testspriteminimal
 test/testfill
+test/testgesture
 test/*.exe
 test/*.dSYM
--- a/Makefile.in	Sun Aug 22 11:56:07 2010 -0700
+++ b/Makefile.in	Sun Aug 22 12:07:55 2010 -0700
@@ -44,7 +44,7 @@
 
 DIST = acinclude autogen.sh Borland.html Borland.zip BUGS build-scripts configure configure.in COPYING CREDITS include INSTALL Makefile.minimal Makefile.in README* sdl-config.in sdl.m4 sdl.pc.in SDL.spec SDL.spec.in src test TODO VisualC.html VisualC VisualCE Watcom-Win32.zip WhatsNew Xcode Xcode-iPhoneOS
 
-HDRS = SDL.h SDL_assert.h SDL_atomic.h SDL_audio.h SDL_clipboard.h SDL_compat.h SDL_cpuinfo.h SDL_endian.h SDL_error.h SDL_events.h SDL_haptic.h SDL_input.h SDL_joystick.h SDL_keyboard.h SDL_keysym.h SDL_loadso.h SDL_main.h SDL_mouse.h SDL_mutex.h SDL_name.h SDL_opengl.h SDL_opengles.h SDL_pixels.h SDL_platform.h SDL_power.h SDL_quit.h SDL_rect.h SDL_revision.h SDL_rwops.h SDL_scancode.h SDL_stdinc.h SDL_surface.h SDL_syswm.h SDL_thread.h SDL_timer.h SDL_types.h SDL_version.h SDL_video.h begin_code.h close_code.h
+HDRS = SDL.h SDL_assert.h SDL_atomic.h SDL_audio.h SDL_clipboard.h SDL_compat.h SDL_cpuinfo.h SDL_endian.h SDL_error.h SDL_events.h SDL_gesture.h SDL_haptic.h SDL_input.h SDL_joystick.h SDL_keyboard.h SDL_keysym.h SDL_loadso.h SDL_main.h SDL_mouse.h SDL_mutex.h SDL_name.h SDL_opengl.h SDL_opengles.h SDL_pixels.h SDL_platform.h SDL_power.h SDL_quit.h SDL_rect.h SDL_revision.h SDL_rwops.h SDL_scancode.h SDL_stdinc.h SDL_surface.h SDL_syswm.h SDL_thread.h SDL_timer.h SDL_touch.h SDL_types.h SDL_version.h SDL_video.h begin_code.h close_code.h
 
 LT_AGE      = @LT_AGE@
 LT_CURRENT  = @LT_CURRENT@
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README.gesture	Sun Aug 22 12:07:55 2010 -0700
@@ -0,0 +1,72 @@
+===========================================================================
+Dollar Gestures
+===========================================================================
+SDL Provides an implementation of the $1 gesture recognition system. This allows for recording, saving, loading, and performing single stroke gestures.
+
+Gestures can be performed with any number of fingers (the centroid of the fingers must follow the path of the gesture), but the number of fingers must be constant (a finger cannot go down in the middle of a gesture). The path of a gesture is considered the path from the time when the final finger went down, to the first time any finger comes up. 
+
+Dollar gestures are assigned an Id based on a hash function. This is guaranteed to remain constant for a given gesture. There is a (small) chance that two different gestures will be assigned the same ID. In this case, simply re-recording one of the gestures should result in a different ID.
+
+Recording:
+----------
+To begin recording on a touch device call:
+SDL_RecordGesture(SDL_TouchID touchId), where touchId is the id of the touch device you wish to record on, or -1 to record on all connected devices.
+
+Recording terminates as soon as a finger comes up. Recording is acknowledged by an SDL_DOLLARRECORD event.
+A SDL_DOLLARRECORD event is a dgesture with the following fields:
+
+event.dgesture.touchId   - the Id of the touch used to record the gesture.
+event.dgesture.gestureId - the unique id of the recoreded gesture.
+
+
+Performing:
+-----------
+As long as there is a dollar gesture assigned to a touch, every finger-up event will also cause an SDL_DOLLARGESTURE event with the following fields:
+
+event.dgesture.touchId    - the Id of the touch which performed the gesture.
+event.dgesture.gestureId  - the unique id of the closest gesture to the performed stroke.
+event.dgesture.error      - the difference between the gesture template and the actual performed gesture. Lower error is a better match.
+event.dgesture.numFingers - the number of fingers used to draw the stroke.
+
+Most programs will want to define an appropriate error threshold and check to be sure taht the error of a gesture is not abnormally high (an indicator that no gesture was performed). 
+
+
+
+Saving:
+-------
+To save a template, call SDL_SaveDollarTemplate(gestureId, src) where gestureId is the id of the gesture you want to save, and src is an SDL_RWops pointer to the file where the gesture will be stored.
+
+To save all currently loaded templates, call SDL_SaveAllDollarTemplates(src) where source is an SDL_RWops pointer to the file where the gesture will be stored.
+
+Both functions return the number of gestures sucessfully saved.
+
+
+Loading:
+--------
+To load templates from a file, call SDL_LoadDollarTemplates(touchId,src) where touchId is the id of the touch to load to (or -1 to load to all touch devices), and src is an SDL_RWops pointer to a gesture save file. 
+
+SDL_LoadDollarTemplates returns the number of templates sucessfully loaded. 
+
+
+
+===========================================================================
+Multi Gestures
+===========================================================================
+SDL provides simple support for pinch/rotate/swipe gestures. 
+Every time a finger is moved an SDL_MULTIGESTURE event is sent with the following fields:
+
+event.mgesture.touchId - the Id of the touch on which the gesture was performed.
+event.mgesture.x       - the normalized x cooridinate of the gesture. (0..1)
+event.mgesture.y       - the normalized y cooridinate of the gesture. (0..1)
+event.mgesture.dTheta  - the amount that the fingers rotated during this motion.
+event.mgesture.dDist   - the amount that the fingers pinched during this motion.
+event.mgesture.numFingers - the number of fingers used in the gesture.
+
+
+===========================================================================
+Notes
+===========================================================================
+For a complete example see test/testgesture.c
+
+Please direct questions/comments to:
+   jim.tla+sdl_touch@gmail.com
--- a/README.iphoneos	Sun Aug 22 11:56:07 2010 -0700
+++ b/README.iphoneos	Sun Aug 22 12:07:55 2010 -0700
@@ -34,14 +34,6 @@
 5.  Delete the contents of main.m and program your app as a regular SDL program instead.  You may replace main.m with your own main.c, but you must tell XCode not to use the project prefix file, as it includes Objective-C code.
 
 ==============================================================================
-Notes -- Touch Input
-==============================================================================
-
-Touch input in SDL for iPhone OS is presently exposed through SDL's mouse input API.  Multi-touch input is reported as multiple mice, with each touch associated with a specific mouse.  This association stays coherent from the time the touch starts to the time a touch ends.
-
-By default, multi-touch is turned ON.  This requires some care, because if you simply respond to mouse events without checking which mouse caused the event, you may end up fetching data from the wrong mouse, ie, from an incorrect or invalid touch.  To turn multi-touch OFF, you can recompile SDL for iPhone with the macro SDL_IPHONE_MULTIPLE_MICE (found in SDL_config_iphoneos.h) set to 0.
-
-==============================================================================
 Notes -- Accelerometer as Joystick
 ==============================================================================
 
@@ -55,7 +47,7 @@
 
 Your SDL application for iPhone uses OpenGL ES for video by default.
 
-OpenGL ES for iPhone supports two display pixel formats, RGBA8 and RGB565, which provide a 32 bit and 16 bit color buffer respectively.  By default, the implementation uses RGB565, but you may use RGBA8 by setting each color component to 8 bits in SDL_GL_SetAttribute.
+OpenGL ES for iPhone supports several display pixel formats, such as RGBA8 and RGB565, which provide a 32 bit and 16 bit color buffer respectively.  By default, the implementation uses RGB565, but you may use RGBA8 by setting each color component to 8 bits in SDL_GL_SetAttribute.
 
 If your application doesn't use OpenGL's depth buffer, you may find significant performance improvement by setting SDL_GL_DEPTH_SIZE to 0.
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/README.touch	Sun Aug 22 12:07:55 2010 -0700
@@ -0,0 +1,101 @@
+===========================================================================
+System Specific Notes
+===========================================================================
+Linux:
+The linux touch system is currently based off event streams, and proc/bus/devices. The active user must be given permissions to read /dev/input/TOUCHDEVICE, where TOUCHDEVICE is the event stream for your device. Currently only Wacom tablets are supported. If you have an unsupported tablet contact me at jim.tla+sdl_touch@gmail.com and I will help you get support for it.
+
+Mac: 
+The Mac and Iphone API's are pretty. If your touch device supports them then you'll be fine. If it doesn't, then there isn't much we can do.
+
+iPhone: 
+Works out of box.
+
+Windows:
+Unfortunately there is no windows support as of yet. Support for Windows 7 is planned, but we currently have no way to test. If you have a Windows 7 WM_TOUCH supported device, and are willing to help test please contact me at jim.tla+sdl_touch@gmail.com
+
+===========================================================================
+Events
+===========================================================================
+SDL_FINGERDOWN:
+Sent when a finger (or stylus) is placed on a touch device.
+Fields:
+event.tfinger.touchId  - the Id of the touch device.
+event.tfinger.fingerId - the Id of the finger which just went down.
+event.tfinger.x        - the x coordinate of the touch (0..touch.xres)
+event.tfinger.y        - the y coordinate of the touch (0..touch.yres)
+event.tfinger.pressure - the pressure of the touch (0..touch.pressureres)
+
+SDL_FINGERMOTION:
+Sent when a finger (or stylus) is moved on the touch device.
+Fields:
+Same as FINGERDOWN but with additional:
+event.tfginer.dx       - change in x coordinate during this motion event.
+event.tfginer.dy       - change in y coordinate during this motion event.
+
+SDL_FINGERMOTION:
+Sent when a finger (or stylus) is lifted from the touch device.
+Fields:
+Same as FINGERDOWN.
+
+
+===========================================================================
+Functions
+===========================================================================
+SDL provides the ability to access the underlying Touch and Finger structures.
+These structures should _never_ be modified.
+
+The following functions are included from SDL_Touch.h
+
+To get a SDL_Touch device call SDL_GetTouch(touchId). 
+This returns an SDL_Touch*. 
+IMPORTANT: If the touch has been removed, or there is no touch with the given ID, SDL_GetTouch will return null. Be sure to check for this!
+
+An SDL_Touch has the following fields:
+>xres,yres,pressures:
+	The resolution at which x,y, and pressure values are reported. Currently these will always be equal to 2^15, but this may not always be the case. 
+
+>pressure_max, pressure_min, x_max, x_min, y_max, y_min
+	Which give, respectively, the maximum and minumum values that the touch digitizer can return for pressure, x coordiniate, and y coordinate AS REPORTED BY THE OPERATING SYSTEM.
+On Mac/iPhone systems _max will always be 0, and _min will always be 1. 
+
+>native_xres,native_yres,native_pressureres:
+	The native resolution of the touch device AS REPORTED BY THE OPERATING SYSTEM.
+On Mac/iPhone systems these will always be 1.
+
+>num_fingers:
+	The number of fingers currently down on the device.
+
+>fingers:
+	An array of pointers to the fingers which are on the device.
+
+
+The most common reason to access a touch device is to normalize inputs. This would be accomplished by code like the following:
+
+      SDL_Touch* inTouch = SDL_GetTouch(event.tfinger.touchId);
+      if(inTouch == NULL) continue; //The touch has been removed
+
+      float x = ((float)event.tfinger.x)/inTouch->xres;
+      float y = ((float)event.tfinger.y)/inTouch->yres;
+
+
+
+To get an SDL_Finger, call SDL_GetFinger(touch,fingerId), where touch is a pointer to an SDL_Touch device, and fingerId is the id of the requested finger.
+This returns an SDL_Finger*, or null if the finger does not exist, or has been removed.
+An SDL_Finger is guaranteed to be persistent for the duration of a touch, but it will be de-allocated as soon as the finger is removed. This occurs when the SDL_FINGERUP event is _added_ to the event queue, and thus _before_ the FINGERUP event is polled. 
+As a result, be very careful to check for null return values.
+
+An SDL_Finger has the following fields:
+>x,y,pressure:
+	The current coordinates of the touch.
+>xdelta,ydelta: 
+	The change in position resulting from the last finger motion.
+>last_x, last_y, last_pressure:
+	 The previous coordinates of the touch.
+
+===========================================================================
+Notes
+===========================================================================
+For a complete example see test/testgesture.c
+
+Please direct questions/comments to:
+   jim.tla+sdl_touch@gmail.com
--- a/VisualC/SDL/SDL_VS2005.vcproj	Sun Aug 22 11:56:07 2010 -0700
+++ b/VisualC/SDL/SDL_VS2005.vcproj	Sun Aug 22 12:07:55 2010 -0700
@@ -1,10 +1,18 @@
 <?xml version="1.0" encoding="Windows-1252"?>
 <VisualStudioProject
 	ProjectType="Visual C++"
+<<<<<<< local
 	Version="8.00"
+=======
+	Version="9.00"
+>>>>>>> other
 	Name="SDL"
 	ProjectGUID="{81CE8DAF-EBB2-4761-8E45-B71ABCCA8C68}"
 	RootNamespace="SDL"
+<<<<<<< local
+=======
+	TargetFrameworkVersion="131072"
+>>>>>>> other
 	>
 	<Platforms>
 		<Platform
@@ -76,16 +84,36 @@
 			/>
 			<Tool
 				Name="VCLinkerTool"
+<<<<<<< local
 				AdditionalOptions="/MACHINE:I386"
+=======
+				AdditionalOptions="/MACHINE:I386&#x0D;&#x0A;msvcrt.lib"
+>>>>>>> other
 				AdditionalDependencies="msimg32.lib winmm.lib"
 				OutputFile=".\Debug/SDL.dll"
 				LinkIncremental="2"
 				SuppressStartupBanner="true"
+<<<<<<< local
 				IgnoreAllDefaultLibraries="true"
+=======
+				IgnoreAllDefaultLibraries="false"
+				IgnoreDefaultLibraryNames=""
+>>>>>>> other
 				GenerateDebugInformation="true"
 				ProgramDatabaseFile=".\Debug/SDL.pdb"
+<<<<<<< local
 				SubSystem="2"
+=======
+				SubSystem="0"
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+>>>>>>> other
 				ImportLibrary=".\Debug/SDL.lib"
+<<<<<<< local
+=======
+				Profile="true"
+				CLRThreadAttribute="0"
+>>>>>>> other
 				CLRUnmanagedCodeCheck="false"
 			/>
 			<Tool
@@ -107,9 +135,12 @@
 				Name="VCAppVerifierTool"
 			/>
 			<Tool
+<<<<<<< local
 				Name="VCWebDeploymentTool"
 			/>
 			<Tool
+=======
+>>>>>>> other
 				Name="VCPostBuildEventTool"
 			/>
 		</Configuration>
@@ -185,6 +216,11 @@
 				IgnoreAllDefaultLibraries="true"
 				ProgramDatabaseFile=".\Release/SDL.pdb"
 				SubSystem="2"
+<<<<<<< local
+=======
+				RandomizedBaseAddress="1"
+				DataExecutionPrevention="0"
+>>>>>>> other
 				ImportLibrary=".\Release/SDL.lib"
 			/>
 			<Tool
@@ -206,9 +242,12 @@
 				Name="VCAppVerifierTool"
 			/>
 			<Tool
+<<<<<<< local
 				Name="VCWebDeploymentTool"
 			/>
 			<Tool
+=======
+>>>>>>> other
 				Name="VCPostBuildEventTool"
 			/>
 		</Configuration>
@@ -941,6 +980,17 @@
 			>
 		</File>
 		<File
+<<<<<<< local
+=======
+			RelativePath="..\..\src\events\SDL_touch.c"
+			>
+		</File>
+		<File
+			RelativePath="..\..\src\events\SDL_touch_c.h"
+			>
+		</File>
+		<File
+>>>>>>> other
 			RelativePath="..\..\src\video\SDL_video.c"
 			>
 		</File>
--- a/VisualC/SDLmain/SDLmain_VS2005.vcproj	Sun Aug 22 11:56:07 2010 -0700
+++ b/VisualC/SDLmain/SDLmain_VS2005.vcproj	Sun Aug 22 12:07:55 2010 -0700
@@ -1,9 +1,17 @@
 <?xml version="1.0" encoding="Windows-1252"?>
 <VisualStudioProject
 	ProjectType="Visual C++"
+<<<<<<< local
 	Version="8.00"
+=======
+	Version="9.00"
+>>>>>>> other
 	Name="SDLmain"
 	ProjectGUID="{DA956FD3-E142-46F2-9DD5-C78BEBB56B7A}"
+<<<<<<< local
+=======
+	TargetFrameworkVersion="131072"
+>>>>>>> other
 	>
 	<Platforms>
 		<Platform
@@ -25,7 +33,11 @@
 			<Tool
 				Name="VCPreBuildEventTool"
 				Description="Making sure basic SDL headers are in place..."
+<<<<<<< local
 				CommandLine="if exist &quot;$(ProjectDir)\..\..\include\SDL_config.h&quot; goto SDLCONFIGOKAY&#x0D;&#x0A;echo Copying SDL_config_win32.h to SDL_config.h...&#x0D;&#x0A;copy &quot;$(ProjectDir)\..\..\include\SDL_config_win32.h&quot; &quot;$(ProjectDir)\..\..\include\SDL_config.h&quot;&#x0D;&#x0A;:SDLCONFIGOKAY&#x0D;&#x0A;&#x0D;&#x0A;if exist &quot;$(ProjectDir)\..\..\include\SDL_revision.h&quot; goto SDLREVISIONOKAY&#x0D;&#x0A;echo Creating stub SDL_revision.h file...&#x0D;&#x0A;echo #define SDL_REVISION 0 &gt;&quot;$(ProjectDir)\..\..\include\SDL_revision.h&quot;&#x0D;&#x0A;:SDLREVISIONOKAY"
+=======
+				CommandLine="if exist &quot;$(ProjectDir)\..\..\include\SDL_config.h&quot; goto SDLCONFIGOKAY&#x0D;&#x0A;echo Copying SDL_config_win32.h to SDL_config.h...&#x0D;&#x0A;copy &quot;$(ProjectDir)\..\..\include\SDL_config_win32.h&quot; &quot;$(ProjectDir)\..\..\include\SDL_config.h&quot;&#x0D;&#x0A;:SDLCONFIGOKAY&#x0D;&#x0A;&#x0D;&#x0A;if exist &quot;$(ProjectDir)\..\..\include\SDL_revision.h&quot; goto SDLREVISIONOKAY&#x0D;&#x0A;echo Creating stub SDL_revision.h file...&#x0D;&#x0A;echo #define SDL_REVISION 0 &gt;&quot;$(ProjectDir)\..\..\include\SDL_revision.h&quot;&#x0D;&#x0A;:SDLREVISIONOKAY&#x0D;&#x0A;"
+>>>>>>> other
 			/>
 			<Tool
 				Name="VCCustomBuildTool"
@@ -98,7 +110,11 @@
 			<Tool
 				Name="VCPreBuildEventTool"
 				Description="Making sure basic SDL headers are in place..."
+<<<<<<< local
 				CommandLine="if exist &quot;$(ProjectDir)\..\..\include\SDL_config.h&quot; goto SDLCONFIGOKAY&#x0D;&#x0A;echo Copying SDL_config_win32.h to SDL_config.h...&#x0D;&#x0A;copy &quot;$(ProjectDir)\..\..\include\SDL_config_win32.h&quot; &quot;$(ProjectDir)\..\..\include\SDL_config.h&quot;&#x0D;&#x0A;:SDLCONFIGOKAY&#x0D;&#x0A;&#x0D;&#x0A;if exist &quot;$(ProjectDir)\..\..\include\SDL_revision.h&quot; goto SDLREVISIONOKAY&#x0D;&#x0A;echo Creating stub SDL_revision.h file...&#x0D;&#x0A;echo #define SDL_REVISION 0 &gt;&quot;$(ProjectDir)\..\..\include\SDL_revision.h&quot;&#x0D;&#x0A;:SDLREVISIONOKAY"
+=======
+				CommandLine="if exist &quot;$(ProjectDir)\..\..\include\SDL_config.h&quot; goto SDLCONFIGOKAY&#x0D;&#x0A;echo Copying SDL_config_win32.h to SDL_config.h...&#x0D;&#x0A;copy &quot;$(ProjectDir)\..\..\include\SDL_config_win32.h&quot; &quot;$(ProjectDir)\..\..\include\SDL_config.h&quot;&#x0D;&#x0A;:SDLCONFIGOKAY&#x0D;&#x0A;&#x0D;&#x0A;if exist &quot;$(ProjectDir)\..\..\include\SDL_revision.h&quot; goto SDLREVISIONOKAY&#x0D;&#x0A;echo Creating stub SDL_revision.h file...&#x0D;&#x0A;echo #define SDL_REVISION 0 &gt;&quot;$(ProjectDir)\..\..\include\SDL_revision.h&quot;&#x0D;&#x0A;:SDLREVISIONOKAY&#x0D;&#x0A;"
+>>>>>>> other
 			/>
 			<Tool
 				Name="VCCustomBuildTool"
@@ -171,7 +187,11 @@
 			<Tool
 				Name="VCPreBuildEventTool"
 				Description="Making sure basic SDL headers are in place..."
+<<<<<<< local
 				CommandLine="if exist &quot;$(ProjectDir)\..\..\include\SDL_config.h&quot; goto SDLCONFIGOKAY&#x0D;&#x0A;echo Copying SDL_config_win32.h to SDL_config.h...&#x0D;&#x0A;copy &quot;$(ProjectDir)\..\..\include\SDL_config_win32.h&quot; &quot;$(ProjectDir)\..\..\include\SDL_config.h&quot;&#x0D;&#x0A;:SDLCONFIGOKAY&#x0D;&#x0A;&#x0D;&#x0A;if exist &quot;$(ProjectDir)\..\..\include\SDL_revision.h&quot; goto SDLREVISIONOKAY&#x0D;&#x0A;echo Creating stub SDL_revision.h file...&#x0D;&#x0A;echo #define SDL_REVISION 0 &gt;&quot;$(ProjectDir)\..\..\include\SDL_revision.h&quot;&#x0D;&#x0A;:SDLREVISIONOKAY"
+=======
+				CommandLine="if exist &quot;$(ProjectDir)\..\..\include\SDL_config.h&quot; goto SDLCONFIGOKAY&#x0D;&#x0A;echo Copying SDL_config_win32.h to SDL_config.h...&#x0D;&#x0A;copy &quot;$(ProjectDir)\..\..\include\SDL_config_win32.h&quot; &quot;$(ProjectDir)\..\..\include\SDL_config.h&quot;&#x0D;&#x0A;:SDLCONFIGOKAY&#x0D;&#x0A;&#x0D;&#x0A;if exist &quot;$(ProjectDir)\..\..\include\SDL_revision.h&quot; goto SDLREVISIONOKAY&#x0D;&#x0A;echo Creating stub SDL_revision.h file...&#x0D;&#x0A;echo #define SDL_REVISION 0 &gt;&quot;$(ProjectDir)\..\..\include\SDL_revision.h&quot;&#x0D;&#x0A;:SDLREVISIONOKAY&#x0D;&#x0A;"
+>>>>>>> other
 			/>
 			<Tool
 				Name="VCCustomBuildTool"
--- a/Xcode-iPhoneOS/Demos/DemosiPhoneOS.xcodeproj/project.pbxproj	Sun Aug 22 11:56:07 2010 -0700
+++ b/Xcode-iPhoneOS/Demos/DemosiPhoneOS.xcodeproj/project.pbxproj	Sun Aug 22 12:07:55 2010 -0700
@@ -109,7 +109,7 @@
 			isa = PBXContainerItemProxy;
 			containerPortal = FD1B48920E313154007AB34E /* SDLiPhoneOS.xcodeproj */;
 			proxyType = 2;
-			remoteGlobalIDString = 006E982211955059001DE610 /* testsdl.app */;
+			remoteGlobalIDString = 006E982211955059001DE610;
 			remoteInfo = testsdl;
 		};
 		FD1B489D0E313154007AB34E /* PBXContainerItemProxy */ = {
--- a/Xcode-iPhoneOS/SDL/SDLiPhoneOS.xcodeproj/project.pbxproj	Sun Aug 22 11:56:07 2010 -0700
+++ b/Xcode-iPhoneOS/SDL/SDLiPhoneOS.xcodeproj/project.pbxproj	Sun Aug 22 12:07:55 2010 -0700
@@ -95,6 +95,12 @@
 		04B2ECEE1025CE4800F9BC5F /* SDL_revision.h in Headers */ = {isa = PBXBuildFile; fileRef = 04B2ECE81025CE4800F9BC5F /* SDL_revision.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		04B2ECFF1025CEB900F9BC5F /* SDL_atomic.c in Sources */ = {isa = PBXBuildFile; fileRef = 04B2ECF11025CEB900F9BC5F /* SDL_atomic.c */; };
 		04B2ED081025CF9E00F9BC5F /* SDL_config.h in Headers */ = {isa = PBXBuildFile; fileRef = 04B2ED061025CF9E00F9BC5F /* SDL_config.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		04BA9D6311EF474A00B60E01 /* SDL_gesture_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BA9D5F11EF474A00B60E01 /* SDL_gesture_c.h */; };
+		04BA9D6411EF474A00B60E01 /* SDL_gesture.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BA9D6011EF474A00B60E01 /* SDL_gesture.c */; };
+		04BA9D6511EF474A00B60E01 /* SDL_touch_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BA9D6111EF474A00B60E01 /* SDL_touch_c.h */; };
+		04BA9D6611EF474A00B60E01 /* SDL_touch.c in Sources */ = {isa = PBXBuildFile; fileRef = 04BA9D6211EF474A00B60E01 /* SDL_touch.c */; };
+		04BA9D7D11EF497E00B60E01 /* SDL_gesture.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BA9D7B11EF497E00B60E01 /* SDL_gesture.h */; };
+		04BA9D7E11EF497E00B60E01 /* SDL_touch.h in Headers */ = {isa = PBXBuildFile; fileRef = 04BA9D7C11EF497E00B60E01 /* SDL_touch.h */; };
 		04EC8B521025D12900431D42 /* SDL_config_iphoneos.h in Headers */ = {isa = PBXBuildFile; fileRef = 04EC8B501025D12900431D42 /* SDL_config_iphoneos.h */; };
 		04F2AF541104ABC300D6DDF7 /* SDL_assert.h in Headers */ = {isa = PBXBuildFile; fileRef = 04F2AF531104ABC300D6DDF7 /* SDL_assert.h */; };
 		04F2AF561104ABD200D6DDF7 /* SDL_assert.c in Sources */ = {isa = PBXBuildFile; fileRef = 04F2AF551104ABD200D6DDF7 /* SDL_assert.c */; };
@@ -346,6 +352,12 @@
 		04B2ECE81025CE4800F9BC5F /* SDL_revision.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDL_revision.h; path = ../../include/SDL_revision.h; sourceTree = SOURCE_ROOT; };
 		04B2ECF11025CEB900F9BC5F /* SDL_atomic.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_atomic.c; sourceTree = "<group>"; };
 		04B2ED061025CF9E00F9BC5F /* SDL_config.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDL_config.h; path = ../../include/SDL_config.h; sourceTree = SOURCE_ROOT; };
+		04BA9D5F11EF474A00B60E01 /* SDL_gesture_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_gesture_c.h; sourceTree = "<group>"; };
+		04BA9D6011EF474A00B60E01 /* SDL_gesture.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_gesture.c; sourceTree = "<group>"; };
+		04BA9D6111EF474A00B60E01 /* SDL_touch_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_touch_c.h; sourceTree = "<group>"; };
+		04BA9D6211EF474A00B60E01 /* SDL_touch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_touch.c; sourceTree = "<group>"; };
+		04BA9D7B11EF497E00B60E01 /* SDL_gesture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDL_gesture.h; path = ../../include/SDL_gesture.h; sourceTree = SOURCE_ROOT; };
+		04BA9D7C11EF497E00B60E01 /* SDL_touch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDL_touch.h; path = ../../include/SDL_touch.h; sourceTree = SOURCE_ROOT; };
 		04EC8B501025D12900431D42 /* SDL_config_iphoneos.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDL_config_iphoneos.h; path = ../../include/SDL_config_iphoneos.h; sourceTree = SOURCE_ROOT; };
 		04F2AF531104ABC300D6DDF7 /* SDL_assert.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDL_assert.h; path = ../../include/SDL_assert.h; sourceTree = SOURCE_ROOT; };
 		04F2AF551104ABD200D6DDF7 /* SDL_assert.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = SDL_assert.c; path = ../../src/SDL_assert.c; sourceTree = SOURCE_ROOT; };
@@ -851,6 +863,7 @@
 				FD99B8F60DD52EB400FB1D6B /* SDL_endian.h */,
 				FD99B8DC0DD52EB400FB1D6B /* SDL_error.h */,
 				FD99B8DD0DD52EB400FB1D6B /* SDL_events.h */,
+				04BA9D7B11EF497E00B60E01 /* SDL_gesture.h */,
 				04461DED0EA76BA3006C462D /* SDL_haptic.h */,
 				044E5FB411E6069F0076F181 /* SDL_input.h */,
 				FD99B8DE0DD52EB400FB1D6B /* SDL_joystick.h */,
@@ -876,6 +889,7 @@
 				FD99B8EF0DD52EB400FB1D6B /* SDL_syswm.h */,
 				FD99B8F00DD52EB400FB1D6B /* SDL_thread.h */,
 				FD99B8F10DD52EB400FB1D6B /* SDL_timer.h */,
+				04BA9D7C11EF497E00B60E01 /* SDL_touch.h */,
 				FD99B8F20DD52EB400FB1D6B /* SDL_types.h */,
 				FD99B8F30DD52EB400FB1D6B /* SDL_version.h */,
 				FD99B8F40DD52EB400FB1D6B /* SDL_video.h */,
@@ -956,6 +970,10 @@
 		FD99B98C0DD52EDC00FB1D6B /* events */ = {
 			isa = PBXGroup;
 			children = (
+				04BA9D5F11EF474A00B60E01 /* SDL_gesture_c.h */,
+				04BA9D6011EF474A00B60E01 /* SDL_gesture.c */,
+				04BA9D6111EF474A00B60E01 /* SDL_touch_c.h */,
+				04BA9D6211EF474A00B60E01 /* SDL_touch.c */,
 				FD99B98D0DD52EDC00FB1D6B /* blank_cursor.h */,
 				FD99B98E0DD52EDC00FB1D6B /* default_cursor.h */,
 				FD99B98F0DD52EDC00FB1D6B /* scancodes_darwin.h */,
@@ -1191,6 +1209,10 @@
 				044E5FB511E6069F0076F181 /* SDL_clipboard.h in Headers */,
 				044E5FB611E6069F0076F181 /* SDL_input.h in Headers */,
 				0420497011E6F03D007E7EC9 /* SDL_clipboardevents_c.h in Headers */,
+				04BA9D6311EF474A00B60E01 /* SDL_gesture_c.h in Headers */,
+				04BA9D6511EF474A00B60E01 /* SDL_touch_c.h in Headers */,
+				04BA9D7D11EF497E00B60E01 /* SDL_gesture.h in Headers */,
+				04BA9D7E11EF497E00B60E01 /* SDL_touch.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -1431,6 +1453,8 @@
 				006E9889119552DD001DE610 /* SDL_rwopsbundlesupport.m in Sources */,
 				044E5FB811E606EB0076F181 /* SDL_clipboard.c in Sources */,
 				0420497111E6F03D007E7EC9 /* SDL_clipboardevents.c in Sources */,
+				04BA9D6411EF474A00B60E01 /* SDL_gesture.c in Sources */,
+				04BA9D6611EF474A00B60E01 /* SDL_touch.c in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
--- a/Xcode/SDL/SDL.xcodeproj/project.pbxproj	Sun Aug 22 11:56:07 2010 -0700
+++ b/Xcode/SDL/SDL.xcodeproj/project.pbxproj	Sun Aug 22 12:07:55 2010 -0700
@@ -476,6 +476,16 @@
 		04F2AF671104AC0800D6DDF7 /* SDL_assert.c in Sources */ = {isa = PBXBuildFile; fileRef = 04F2AF651104AC0800D6DDF7 /* SDL_assert.c */; };
 		04F2AF691104AC4500D6DDF7 /* SDL_assert.h in Headers */ = {isa = PBXBuildFile; fileRef = 04F2AF681104AC4500D6DDF7 /* SDL_assert.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		04F2AF6A1104AC4500D6DDF7 /* SDL_assert.h in Headers */ = {isa = PBXBuildFile; fileRef = 04F2AF681104AC4500D6DDF7 /* SDL_assert.h */; };
+		8CB0A76C11F6A84800CBA2DE /* SDL_x11clipboard.c in Sources */ = {isa = PBXBuildFile; fileRef = 8CB0A76A11F6A84800CBA2DE /* SDL_x11clipboard.c */; };
+		8CB0A76D11F6A84800CBA2DE /* SDL_x11clipboard.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CB0A76B11F6A84800CBA2DE /* SDL_x11clipboard.h */; };
+		8CB0A77811F6A87F00CBA2DE /* SDL_gesture.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CB0A77611F6A87F00CBA2DE /* SDL_gesture.h */; };
+		8CB0A77911F6A87F00CBA2DE /* SDL_touch.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CB0A77711F6A87F00CBA2DE /* SDL_touch.h */; };
+		8CB0A77E11F6A8E700CBA2DE /* SDL_gesture_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CB0A77A11F6A8E700CBA2DE /* SDL_gesture_c.h */; };
+		8CB0A77F11F6A8E700CBA2DE /* SDL_gesture.c in Sources */ = {isa = PBXBuildFile; fileRef = 8CB0A77B11F6A8E700CBA2DE /* SDL_gesture.c */; };
+		8CB0A78011F6A8E700CBA2DE /* SDL_touch_c.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CB0A77C11F6A8E700CBA2DE /* SDL_touch_c.h */; };
+		8CB0A78111F6A8E700CBA2DE /* SDL_touch.c in Sources */ = {isa = PBXBuildFile; fileRef = 8CB0A77D11F6A8E700CBA2DE /* SDL_touch.c */; };
+		8CB0A78711F6A90B00CBA2DE /* SDL_eventtouch.c in Sources */ = {isa = PBXBuildFile; fileRef = 8CB0A78511F6A90B00CBA2DE /* SDL_eventtouch.c */; };
+		8CB0A78811F6A90B00CBA2DE /* SDL_eventtouch.h in Headers */ = {isa = PBXBuildFile; fileRef = 8CB0A78611F6A90B00CBA2DE /* SDL_eventtouch.h */; };
 		BECDF62E0761BA81005FE872 /* SDL_audio.c in Sources */ = {isa = PBXBuildFile; fileRef = 01538330006D78D67F000001 /* SDL_audio.c */; };
 		BECDF62F0761BA81005FE872 /* SDL_audiocvt.c in Sources */ = {isa = PBXBuildFile; fileRef = 01538331006D78D67F000001 /* SDL_audiocvt.c */; };
 		BECDF6300761BA81005FE872 /* SDL_audiodev.c in Sources */ = {isa = PBXBuildFile; fileRef = 01538332006D78D67F000001 /* SDL_audiodev.c */; };
@@ -864,6 +874,17 @@
 		0C5AF5FD01191D2B7F000001 /* SDL_version.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SDL_version.h; path = ../../include/SDL_version.h; sourceTree = SOURCE_ROOT; };
 		0C5AF5FE01191D2B7F000001 /* SDL_video.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SDL_video.h; path = ../../include/SDL_video.h; sourceTree = SOURCE_ROOT; };
 		0C5AF5FF01191D2B7F000001 /* SDL.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SDL.h; path = ../../include/SDL.h; sourceTree = SOURCE_ROOT; };
+		8C93F0EA11F803710014F54D /* gestureSDLTest-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "gestureSDLTest-Info.plist"; sourceTree = "<group>"; };
+		8CB0A76A11F6A84800CBA2DE /* SDL_x11clipboard.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_x11clipboard.c; sourceTree = "<group>"; };
+		8CB0A76B11F6A84800CBA2DE /* SDL_x11clipboard.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_x11clipboard.h; sourceTree = "<group>"; };
+		8CB0A77611F6A87F00CBA2DE /* SDL_gesture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDL_gesture.h; path = ../../include/SDL_gesture.h; sourceTree = SOURCE_ROOT; };
+		8CB0A77711F6A87F00CBA2DE /* SDL_touch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SDL_touch.h; path = ../../include/SDL_touch.h; sourceTree = SOURCE_ROOT; };
+		8CB0A77A11F6A8E700CBA2DE /* SDL_gesture_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_gesture_c.h; sourceTree = "<group>"; };
+		8CB0A77B11F6A8E700CBA2DE /* SDL_gesture.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_gesture.c; sourceTree = "<group>"; };
+		8CB0A77C11F6A8E700CBA2DE /* SDL_touch_c.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_touch_c.h; sourceTree = "<group>"; };
+		8CB0A77D11F6A8E700CBA2DE /* SDL_touch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_touch.c; sourceTree = "<group>"; };
+		8CB0A78511F6A90B00CBA2DE /* SDL_eventtouch.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; path = SDL_eventtouch.c; sourceTree = "<group>"; };
+		8CB0A78611F6A90B00CBA2DE /* SDL_eventtouch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SDL_eventtouch.h; sourceTree = "<group>"; };
 		B24DA50405A88D52006B9F1C /* SDL_cpuinfo.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = SDL_cpuinfo.c; sourceTree = "<group>"; };
 		B29A290D04E5B28700A80002 /* SDL_loadso.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SDL_loadso.h; path = ../../include/SDL_loadso.h; sourceTree = "<group>"; };
 		B2CF8DC405C444E400E5DC7F /* SDL_cpuinfo.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = SDL_cpuinfo.h; path = ../../include/SDL_cpuinfo.h; sourceTree = SOURCE_ROOT; };
@@ -1108,6 +1129,10 @@
 		00CFA719106B498B00758660 /* x11 */ = {
 			isa = PBXGroup;
 			children = (
+				8CB0A78511F6A90B00CBA2DE /* SDL_eventtouch.c */,
+				8CB0A78611F6A90B00CBA2DE /* SDL_eventtouch.h */,
+				8CB0A76A11F6A84800CBA2DE /* SDL_x11clipboard.c */,
+				8CB0A76B11F6A84800CBA2DE /* SDL_x11clipboard.h */,
 				00CFA71A106B498B00758660 /* imKStoUCS.c */,
 				00CFA71B106B498B00758660 /* imKStoUCS.h */,
 				00CFA71C106B498B00758660 /* SDL_x11dyn.c */,
@@ -1353,6 +1378,10 @@
 		01538367006D79147F000001 /* events */ = {
 			isa = PBXGroup;
 			children = (
+				8CB0A77A11F6A8E700CBA2DE /* SDL_gesture_c.h */,
+				8CB0A77B11F6A8E700CBA2DE /* SDL_gesture.c */,
+				8CB0A77C11F6A8E700CBA2DE /* SDL_touch_c.h */,
+				8CB0A77D11F6A8E700CBA2DE /* SDL_touch.c */,
 				0420497411E6F052007E7EC9 /* blank_cursor.h */,
 				0420497511E6F052007E7EC9 /* default_cursor.h */,
 				0420497611E6F052007E7EC9 /* scancodes_darwin.h */,
@@ -1470,6 +1499,8 @@
 		0153844A006D81B07F000001 /* Public Headers */ = {
 			isa = PBXGroup;
 			children = (
+				8CB0A77611F6A87F00CBA2DE /* SDL_gesture.h */,
+				8CB0A77711F6A87F00CBA2DE /* SDL_touch.h */,
 				0C5AF5E501191D2B7F000001 /* begin_code.h */,
 				0C5AF5E601191D2B7F000001 /* close_code.h */,
 				0C5AF5FF01191D2B7F000001 /* SDL.h */,
@@ -1561,6 +1592,7 @@
 				BECDF66B0761BA81005FE872 /* Info-Framework.plist */,
 				BEC562FE0761C0E800A33029 /* Linked Frameworks */,
 				00D8D9F11195090700638393 /* testsdl-Info.plist */,
+				8C93F0EA11F803710014F54D /* gestureSDLTest-Info.plist */,
 			);
 			comments = "To build Universal Binaries, we have experimented with a variety of different options.\nThe complication is that we must retain compatibility with at least 10.2. \nThe Universal Binary defaults only work for > 10.3.9\n\nSo far, we have found:\ngcc 4.0.0 with Xcode 2.1 always links against libgcc_s. gcc 4.0.1 from Xcode 2.2 fixes this problem.\n\nBut gcc 4.0 will not work with < 10.3.9 because we continue to get an undefined symbol to _fprintf$LDBL128.\nSo we must use gcc 3.3 on PPC to accomplish 10.2 support. (But 4.0 is required for i386.)\n\nSetting the deployment target to 10.4 will disable prebinding, so for PPC, we set it less than 10.4 to preserve prebinding for legacy support.\n\nSetting the PPC SDKROOT to /Developers/SDKs/MacOSX10.2.8.sdk will link to 63.0.0 libSystem.B.dylib. Leaving it at current or 10.4u links to 88.1.2. However, as long as we are using gcc 3.3, it doesn't seem to matter as testing has demonstrated both will run. We have decided not to invoke the 10.2.8 SDK because it is not a default installed component with Xcode which will probably cause most people problems. However, rather than deleting the SDKROOT_ppc entry entirely, we have mapped it to 10.4u in case we decide we need to change this setting.\n\nTo use Altivec or SSE, we needed architecture specific flags:\nOTHER_CFLAGS_ppc\nOTHER_CFLAGS_i386\nOTHER_CFLAGS=$(OTHER_CFLAGS_($CURRENT_ARCH))\n\nThe general OTHER_CFLAGS needed to be manually mapped to architecture specific options because Xcode didn't do this automatically for us.\n\n\n";
 			name = SDLFramework;
@@ -1805,6 +1837,12 @@
 				0420497D11E6F052007E7EC9 /* scancodes_linux.h in Headers */,
 				0420497E11E6F052007E7EC9 /* scancodes_win32.h in Headers */,
 				0420497F11E6F052007E7EC9 /* scancodes_xfree86.h in Headers */,
+				8CB0A76D11F6A84800CBA2DE /* SDL_x11clipboard.h in Headers */,
+				8CB0A77811F6A87F00CBA2DE /* SDL_gesture.h in Headers */,
+				8CB0A77911F6A87F00CBA2DE /* SDL_touch.h in Headers */,
+				8CB0A77E11F6A8E700CBA2DE /* SDL_gesture_c.h in Headers */,
+				8CB0A78011F6A8E700CBA2DE /* SDL_touch_c.h in Headers */,
+				8CB0A78811F6A90B00CBA2DE /* SDL_eventtouch.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
@@ -2277,6 +2315,10 @@
 				04DEA57511E6009000386CAC /* SDL_clipboard.c in Sources */,
 				04DEA57A11E600A600386CAC /* SDL_cocoaclipboard.m in Sources */,
 				0420496211E6EFD3007E7EC9 /* SDL_clipboardevents.c in Sources */,
+				8CB0A76C11F6A84800CBA2DE /* SDL_x11clipboard.c in Sources */,
+				8CB0A77F11F6A8E700CBA2DE /* SDL_gesture.c in Sources */,
+				8CB0A78111F6A8E700CBA2DE /* SDL_touch.c in Sources */,
+				8CB0A78711F6A90B00CBA2DE /* SDL_eventtouch.c in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
--- a/configure.in	Sun Aug 22 11:56:07 2010 -0700
+++ b/configure.in	Sun Aug 22 12:07:55 2010 -0700
@@ -1005,6 +1005,8 @@
 dnl Find the X11 include and library directories
 CheckX11()
 {
+
+
     AC_ARG_ENABLE(video-x11,
 AC_HELP_STRING([--enable-video-x11], [use X11 video driver [[default=yes]]]),
                   , enable_video_x11=yes)
--- a/include/SDL_events.h	Sun Aug 22 11:56:07 2010 -0700
+++ b/include/SDL_events.h	Sun Aug 22 12:07:55 2010 -0700
@@ -36,6 +36,8 @@
 #include "SDL_mouse.h"
 #include "SDL_joystick.h"
 #include "SDL_quit.h"
+#include "SDL_gesture.h"
+#include "SDL_touch.h"
 
 #include "begin_code.h"
 /* Set up for C function definitions, even when using C++ */
@@ -90,14 +92,28 @@
     SDL_JOYBUTTONDOWN,          /**< Joystick button pressed */
     SDL_JOYBUTTONUP,            /**< Joystick button released */
 
+    /* Touch events */
+    SDL_FINGERDOWN      = 0x700,
+    SDL_FINGERUP,
+    SDL_FINGERMOTION,
+    SDL_TOUCHBUTTONDOWN,
+    SDL_TOUCHBUTTONUP,    
+
+    /* Gesture events */
+    SDL_DOLLARGESTURE   = 0x800,
+    SDL_DOLLARRECORD,
+    SDL_MULTIGESTURE,
+
     /* Clipboard events */
-    SDL_CLIPBOARDUPDATE = 0x700, /**< The clipboard changed */
+
+    SDL_CLIPBOARDUPDATE = 0x900, /**< The clipboard changed */
 
     /* Obsolete events */
     SDL_EVENT_COMPAT1 = 0x7000, /**< SDL 1.2 events for compatibility */
     SDL_EVENT_COMPAT2,
     SDL_EVENT_COMPAT3,
 
+
     /** Events ::SDL_USEREVENT through ::SDL_LASTEVENT are for your use,
      *  and should be allocated with SDL_RegisterEvents()
      */
@@ -263,6 +279,79 @@
     Uint8 padding1;
 } SDL_JoyButtonEvent;
 
+
+/**
+ *  \brief Touch finger motion/finger event structure (event.tmotion.*)
+ */
+typedef struct SDL_TouchFingerEvent
+{
+    Uint32 type;        /**< ::SDL_FINGERMOTION OR 
+			   SDL_FINGERDOWN OR SDL_FINGERUP*/
+    Uint32 windowID;    /**< The window with mouse focus, if any */
+    SDL_TouchID touchId;        /**< The touch device id */
+    SDL_FingerID fingerId;
+    Uint8 state;        /**< The current button state */
+    Uint8 padding1;
+    Uint8 padding2;
+    Uint8 padding3;
+    Uint16 x;
+    Uint16 y;
+    Sint16 dx;
+    Sint16 dy;
+    Uint16 pressure;
+} SDL_TouchFingerEvent;
+
+
+/**
+ *  \brief Touch finger motion/finger event structure (event.tmotion.*)
+ */
+typedef struct SDL_TouchButtonEvent
+{
+    Uint32 type;        /**< ::SDL_TOUCHBUTTONUP OR SDL_TOUCHBUTTONDOWN */
+    Uint32 windowID;    /**< The window with mouse focus, if any */
+    SDL_TouchID touchId;        /**< The touch device index */
+    Uint8 state;        /**< The current button state */
+    Uint8 button;        /**< The button changing state */
+    Uint8 padding1;
+    Uint8 padding2;
+} SDL_TouchButtonEvent;
+
+
+
+/**
+ *  \brief Multiple Finger Gesture Event
+ */
+typedef struct SDL_MultiGestureEvent
+{
+    Uint32 type;        /**< ::SDL_MULTIGESTURE */
+    Uint32 windowID;    /**< The window with mouse focus, if any */
+    SDL_TouchID touchId;        /**< The touch device index */
+    float dTheta;
+    float dDist;
+    float x;  //currently 0...1. Change to screen coords?
+    float y;  
+    Uint16 numFingers;
+    Uint16 padding;
+} SDL_MultiGestureEvent;
+
+typedef struct SDL_DollarGestureEvent
+{
+    Uint32 type;        /**< ::SDL_DOLLARGESTURE */
+    Uint32 windowID;    /**< The window with mouse focus, if any */
+    SDL_TouchID touchId;        /**< The touch device index */
+    SDL_GestureID gestureId;
+    Uint32 numFingers;
+    float error;
+  /*
+    //TODO: Enable to give location?
+    float x;  //currently 0...1. Change to screen coords?
+    float y;  
+  */
+} SDL_DollarGestureEvent;
+
+
+
+
 /**
  *  \brief The "quit requested" event
  */
@@ -345,6 +434,10 @@
     SDL_QuitEvent quit;             /**< Quit request event data */
     SDL_UserEvent user;             /**< Custom event data */
     SDL_SysWMEvent syswm;           /**< System dependent window event data */
+    SDL_TouchFingerEvent tfinger;   /**< Touch finger event data */
+    SDL_TouchButtonEvent tbutton;   /**< Touch button event data */
+    SDL_MultiGestureEvent mgesture; /**< Multi Finger Gesture data*/
+    SDL_DollarGestureEvent dgesture; /**< Multi Finger Gesture data*/
 
     /** Temporarily here for backwards compatibility */
     /*@{*/
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/SDL_gesture.h	Sun Aug 22 12:07:55 2010 -0700
@@ -0,0 +1,92 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997-2010 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+
+/**
+ *  \file SDL_gesture.h
+ *  
+ *  Include file for SDL gesture event handling.
+ */
+
+#ifndef _SDL_gesture_h
+#define _SDL_gesture_h
+
+#include "SDL_stdinc.h"
+#include "SDL_error.h"
+#include "SDL_video.h"
+
+#include "SDL_touch.h"
+
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+extern "C" {
+/* *INDENT-ON* */
+#endif
+
+typedef Sint64 SDL_GestureID;
+
+/* Function prototypes */
+
+/**
+ *  \brief Begin Recording a gesture on the specified touch, or all touches (-1)
+ *
+ *
+ */
+extern DECLSPEC int SDLCALL SDL_RecordGesture(SDL_TouchID touchId);
+
+
+/**
+ *  \brief Save all currently loaded Dollar Gesture templates
+ *
+ *
+ */
+extern DECLSPEC int SDLCALL SDL_SaveAllDollarTemplates(SDL_RWops *src);
+
+/**
+ *  \brief Save a currently loaded Dollar Gesture template
+ *
+ *
+ */
+extern DECLSPEC int SDLCALL SDL_SaveDollarTemplate(SDL_GestureID gestureId,SDL_RWops *src);
+
+
+/**
+ *  \brief Load Dollar Gesture templates from a file
+ *
+ *
+ */
+extern DECLSPEC int SDLCALL SDL_LoadDollarTemplates(SDL_TouchID touchId, SDL_RWops *src);
+
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+}
+/* *INDENT-ON* */
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_gesture_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/include/SDL_touch.h	Sun Aug 22 12:07:55 2010 -0700
@@ -0,0 +1,125 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997-2010 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+
+/**
+ *  \file SDL_touch.h
+ *  
+ *  Include file for SDL touch event handling.
+ */
+
+#ifndef _SDL_touch_h
+#define _SDL_touch_h
+
+#include "SDL_stdinc.h"
+#include "SDL_error.h"
+#include "SDL_video.h"
+
+#include "begin_code.h"
+/* Set up for C function definitions, even when using C++ */
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+extern "C" {
+/* *INDENT-ON* */
+#endif
+
+
+typedef Sint64 SDL_TouchID;
+typedef Sint64 SDL_FingerID;
+
+
+struct SDL_Finger {
+  SDL_FingerID id;
+  Uint16 x;
+  Uint16 y;
+  Uint16 pressure;
+  Uint16 xdelta;
+  Uint16 ydelta;
+  Uint16 last_x, last_y,last_pressure;  /* the last reported coordinates */
+  SDL_bool down;
+};
+
+typedef struct SDL_Touch SDL_Touch;
+typedef struct SDL_Finger SDL_Finger;
+
+
+struct SDL_Touch {
+  
+  /* Free the touch when it's time */
+  void (*FreeTouch) (SDL_Touch * touch);
+  
+  /* data common for tablets */
+  float pressure_max, pressure_min;
+  float x_max,x_min;
+  float y_max,y_min;
+  Uint16 xres,yres,pressureres;
+  float native_xres,native_yres,native_pressureres;
+  float tilt;                   /* for future use */
+  float rotation;               /* for future use */
+  
+  /* Data common to all touch */
+  SDL_TouchID id;
+  SDL_Window *focus;
+  
+  char *name;
+  Uint8 buttonstate;
+  SDL_bool relative_mode;
+  SDL_bool flush_motion;
+
+  int num_fingers;
+  int max_fingers;
+  SDL_Finger** fingers;
+    
+  void *driverdata;
+};
+
+
+
+/* Function prototypes */
+
+/**
+ *  \brief Get the touch object at the given id.
+ *
+ *
+ */
+  extern DECLSPEC SDL_Touch* SDLCALL SDL_GetTouch(SDL_TouchID id);
+
+
+
+/**
+ *  \brief Get the finger object of the given touch, at the given id.
+ *
+ *
+ */
+  extern 
+  DECLSPEC SDL_Finger* SDLCALL SDL_GetFinger(SDL_Touch *touch, SDL_FingerID id);
+
+/* Ends C function definitions when using C++ */
+#ifdef __cplusplus
+/* *INDENT-OFF* */
+}
+/* *INDENT-ON* */
+#endif
+#include "close_code.h"
+
+#endif /* _SDL_mouse_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- a/src/events/SDL_events.c	Sun Aug 22 11:56:07 2010 -0700
+++ b/src/events/SDL_events.c	Sun Aug 22 12:07:55 2010 -0700
@@ -254,6 +254,7 @@
     retcode = 0;
     retcode += SDL_KeyboardInit();
     retcode += SDL_MouseInit();
+    retcode += SDL_TouchInit();
     retcode += SDL_QuitInit();
     if (retcode < 0) {
         /* We don't expect them to fail, but... */
@@ -492,6 +493,10 @@
     if (SDL_PeepEvents(event, 1, SDL_ADDEVENT, 0, 0) <= 0) {
         return -1;
     }
+
+    SDL_GestureProcessEvent(event);
+    
+
     return 1;
 }
 
--- a/src/events/SDL_events_c.h	Sun Aug 22 11:56:07 2010 -0700
+++ b/src/events/SDL_events_c.h	Sun Aug 22 12:07:55 2010 -0700
@@ -26,8 +26,9 @@
 #include "SDL_thread.h"
 #include "SDL_mouse_c.h"
 #include "SDL_keyboard_c.h"
+#include "SDL_touch_c.h"
 #include "SDL_windowevents_c.h"
-
+#include "SDL_gesture_c.h"
 /* Start and stop the event processing loop */
 extern int SDL_StartEventLoop(Uint32 flags);
 extern void SDL_StopEventLoop(void);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/events/SDL_gesture.c	Sun Aug 22 12:07:55 2010 -0700
@@ -0,0 +1,643 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997-2010 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software    Founation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* General mouse handling code for SDL */
+
+#include "SDL_events.h"
+#include "SDL_events_c.h"
+#include "SDL_gesture_c.h"
+
+//TODO: Replace with malloc
+
+#define MAXPATHSIZE 1024
+
+ 
+
+
+#define DOLLARNPOINTS 64
+#define DOLLARSIZE 256
+
+#define ENABLE_DOLLAR
+
+//PHI = ((sqrt(5)-1)/2)
+#define PHI 0.618033989 
+
+typedef struct {
+  float x,y;
+} SDL_FloatPoint;
+
+typedef struct {
+  float length;
+  
+  int numPoints;
+  SDL_FloatPoint p[MAXPATHSIZE];
+} SDL_DollarPath;
+
+typedef struct {
+  SDL_FloatPoint path[DOLLARNPOINTS];
+  unsigned long hash;
+} SDL_DollarTemplate;
+
+typedef struct {
+  SDL_GestureID id;
+  SDL_FloatPoint res;
+  SDL_FloatPoint centroid;
+  SDL_DollarPath dollarPath;
+  Uint16 numDownFingers;
+
+  int numDollarTemplates;
+  SDL_DollarTemplate *dollarTemplate;
+
+  SDL_bool recording;
+} SDL_GestureTouch;
+
+SDL_GestureTouch *SDL_gestureTouch;
+int SDL_numGestureTouches = 0;
+SDL_bool recordAll;
+
+void SDL_PrintPath(SDL_FloatPoint *path) {
+  int i;
+  printf("Path:");
+  for(i=0;i<DOLLARNPOINTS;i++) {
+    printf(" (%f,%f)",path[i].x,path[i].y);
+  }
+  printf("\n");
+}
+
+int SDL_RecordGesture(SDL_TouchID touchId) {
+  int i;
+  if(touchId < 0) recordAll = SDL_TRUE;
+  for(i = 0;i < SDL_numGestureTouches; i++) {
+    if((touchId < 0) || (SDL_gestureTouch[i].id == touchId)) {
+      SDL_gestureTouch[i].recording = SDL_TRUE;
+      if(touchId >= 0)
+	return 1;
+    }      
+  }
+  return (touchId < 0);
+}
+
+unsigned long SDL_HashDollar(SDL_FloatPoint* points) {
+  unsigned long hash = 5381;
+  int i;
+  for(i = 0;i < DOLLARNPOINTS; i++) { 
+    hash = ((hash<<5) + hash) + points[i].x;
+    hash = ((hash<<5) + hash) + points[i].y;
+  }
+  return hash;
+}
+
+
+static int SaveTemplate(SDL_DollarTemplate *templ, SDL_RWops * src) {
+  if(src == NULL) return 0;
+
+  int i;
+  
+  //No Longer storing the Hash, rehash on load
+  //if(SDL_RWops.write(src,&(templ->hash),sizeof(templ->hash),1) != 1) return 0;
+  
+  if(SDL_RWwrite(src,templ->path,
+		 sizeof(templ->path[0]),DOLLARNPOINTS) != DOLLARNPOINTS) 
+    return 0;
+
+  return 1;
+}
+
+
+int SDL_SaveAllDollarTemplates(SDL_RWops *src) {  
+  int i,j,rtrn = 0;
+  for(i = 0; i < SDL_numGestureTouches; i++) {
+    SDL_GestureTouch* touch = &SDL_gestureTouch[i];
+    for(j = 0;j < touch->numDollarTemplates; j++) {
+	rtrn += SaveTemplate(&touch->dollarTemplate[i],src);
+    }
+  }
+  return rtrn;  
+}
+
+int SDL_SaveDollarTemplate(SDL_GestureID gestureId, SDL_RWops *src) {
+  int i,j;
+  for(i = 0; i < SDL_numGestureTouches; i++) {
+    SDL_GestureTouch* touch = &SDL_gestureTouch[i];
+    for(j = 0;j < touch->numDollarTemplates; j++) {
+      if(touch->dollarTemplate[i].hash == gestureId) {
+	return SaveTemplate(&touch->dollarTemplate[i],src);
+      }
+    }
+  }
+  SDL_SetError("Unknown gestureId");
+  return -1;
+}
+
+//path is an already sampled set of points
+//Returns the index of the gesture on success, or -1
+static int SDL_AddDollarGesture(SDL_GestureTouch* inTouch,SDL_FloatPoint* path) {
+  if(inTouch == NULL) {
+    if(SDL_numGestureTouches == 0) return -1;
+    int i = 0;
+    for(i = 0;i < SDL_numGestureTouches; i++) {
+      inTouch = &SDL_gestureTouch[i];
+
+      SDL_DollarTemplate* dollarTemplate = 
+	SDL_realloc(inTouch->dollarTemplate,
+		    (inTouch->numDollarTemplates + 1) * 
+		    sizeof(SDL_DollarTemplate));
+      if(!dollarTemplate) {
+	SDL_OutOfMemory();
+	return -1;
+      }
+	
+      inTouch->dollarTemplate = dollarTemplate;
+
+      SDL_DollarTemplate *templ = 
+	&inTouch->dollarTemplate[inTouch->numDollarTemplates];
+      memcpy(templ->path,path,DOLLARNPOINTS*sizeof(SDL_FloatPoint));
+      templ->hash = SDL_HashDollar(templ->path);
+      inTouch->numDollarTemplates++;    
+    }
+    return inTouch->numDollarTemplates - 1;
+  } else {
+    SDL_DollarTemplate* dollarTemplate = 
+      SDL_realloc(inTouch->dollarTemplate,
+		  (inTouch->numDollarTemplates + 1) * 
+		  sizeof(SDL_DollarTemplate));
+    if(!dollarTemplate) {
+      SDL_OutOfMemory();
+      return -1;
+    }
+    
+    inTouch->dollarTemplate = dollarTemplate;
+
+    SDL_DollarTemplate *templ = 
+      &inTouch->dollarTemplate[inTouch->numDollarTemplates];
+    memcpy(templ->path,path,DOLLARNPOINTS*sizeof(SDL_FloatPoint));
+    templ->hash = SDL_HashDollar(templ->path);
+    inTouch->numDollarTemplates++;
+    return inTouch->numDollarTemplates - 1;
+  }
+  return -1;
+}
+
+int SDL_LoadDollarTemplates(SDL_TouchID touchId, SDL_RWops *src) {
+  if(src == NULL) return 0;
+  int i,loaded = 0;
+  SDL_GestureTouch *touch = NULL;
+  if(touchId >= 0) {
+    for(i = 0;i < SDL_numGestureTouches; i++)
+      if(SDL_gestureTouch[i].id == touchId)
+	touch = &SDL_gestureTouch[i];
+    if(touch == NULL) return -1;
+  }
+
+  while(1) {
+    SDL_DollarTemplate templ;
+
+    if(SDL_RWread(src,templ.path,sizeof(templ.path[0]),DOLLARNPOINTS) < 
+       DOLLARNPOINTS) break;
+
+    if(touchId >= 0) {
+      printf("Adding loaded gesture to 1 touch\n");
+      if(SDL_AddDollarGesture(touch,templ.path)) loaded++;
+    }
+    else {
+      printf("Adding to: %i touches\n",SDL_numGestureTouches);
+      for(i = 0;i < SDL_numGestureTouches; i++) {
+	touch = &SDL_gestureTouch[i];
+	printf("Adding loaded gesture to + touches\n");
+	//TODO: What if this fails?
+	SDL_AddDollarGesture(touch,templ.path);	
+      }
+      loaded++;
+    }
+  }
+
+  return loaded; 
+}
+
+
+float dollarDifference(SDL_FloatPoint* points,SDL_FloatPoint* templ,float ang) {
+  //  SDL_FloatPoint p[DOLLARNPOINTS];
+  float dist = 0;
+  SDL_FloatPoint p;
+  int i;
+  for(i = 0; i < DOLLARNPOINTS; i++) {
+    p.x = points[i].x * cos(ang) - points[i].y * sin(ang);
+    p.y = points[i].x * sin(ang) + points[i].y * cos(ang);
+    dist += sqrt((p.x-templ[i].x)*(p.x-templ[i].x)+
+		 (p.y-templ[i].y)*(p.y-templ[i].y));
+  }
+  return dist/DOLLARNPOINTS;
+  
+}
+
+float bestDollarDifference(SDL_FloatPoint* points,SDL_FloatPoint* templ) {
+  //------------BEGIN DOLLAR BLACKBOX----------------//
+  //-TRANSLATED DIRECTLY FROM PSUDEO-CODE AVAILABLE AT-//
+  //-"http://depts.washington.edu/aimgroup/proj/dollar/"-//
+  float ta = -M_PI/4;
+  float tb = M_PI/4;
+  float dt = M_PI/90;
+  float x1 = PHI*ta + (1-PHI)*tb;
+  float f1 = dollarDifference(points,templ,x1);
+  float x2 = (1-PHI)*ta + PHI*tb;
+  float f2 = dollarDifference(points,templ,x2);
+  while(abs(ta-tb) > dt) {
+    if(f1 < f2) {
+      tb = x2;
+      x2 = x1;
+      f2 = f1;
+      x1 = PHI*ta + (1-PHI)*tb;
+      f1 = dollarDifference(points,templ,x1);
+    }
+    else {
+      ta = x1;
+      x1 = x2;
+      f1 = f2;
+      x2 = (1-PHI)*ta + PHI*tb;
+      f2 = dollarDifference(points,templ,x2);
+    }
+  }
+  /*
+  if(f1 <= f2)
+    printf("Min angle (x1): %f\n",x1);
+  else if(f1 >  f2)
+    printf("Min angle (x2): %f\n",x2);
+  */
+  return SDL_min(f1,f2);  
+}
+
+//DollarPath contains raw points, plus (possibly) the calculated length
+int dollarNormalize(SDL_DollarPath path,SDL_FloatPoint *points) {
+  int i;
+  //Calculate length if it hasn't already been done
+  if(path.length <= 0) {
+    for(i=1;i<path.numPoints;i++) {
+      float dx = path.p[i  ].x - 
+	         path.p[i-1].x;
+      float dy = path.p[i  ].y - 
+	         path.p[i-1].y;
+      path.length += sqrt(dx*dx+dy*dy);
+    }
+  }
+
+  //Resample
+  float interval = path.length/(DOLLARNPOINTS - 1);
+  float dist = interval;
+
+  int numPoints = 0;
+  SDL_FloatPoint centroid; 
+  centroid.x = 0;centroid.y = 0;
+  
+  //printf("(%f,%f)\n",path.p[path.numPoints-1].x,path.p[path.numPoints-1].y);
+  for(i = 1;i < path.numPoints;i++) {
+    float d = sqrt((path.p[i-1].x-path.p[i].x)*(path.p[i-1].x-path.p[i].x)+
+		   (path.p[i-1].y-path.p[i].y)*(path.p[i-1].y-path.p[i].y));
+    //printf("d = %f dist = %f/%f\n",d,dist,interval);
+    while(dist + d > interval) {
+      points[numPoints].x = path.p[i-1].x + 
+	((interval-dist)/d)*(path.p[i].x-path.p[i-1].x);
+      points[numPoints].y = path.p[i-1].y + 
+	((interval-dist)/d)*(path.p[i].y-path.p[i-1].y);
+      centroid.x += points[numPoints].x;
+      centroid.y += points[numPoints].y;
+      numPoints++;
+
+      dist -= interval;
+    }
+    dist += d;
+  }
+  if(numPoints < DOLLARNPOINTS-1) {
+    printf("ERROR: NumPoints = %i\n",numPoints); 
+    return 0;
+  }
+  //copy the last point
+  points[DOLLARNPOINTS-1] = path.p[path.numPoints-1];
+  numPoints = DOLLARNPOINTS;
+
+  centroid.x /= numPoints;
+  centroid.y /= numPoints;
+ 
+  //printf("Centroid (%f,%f)",centroid.x,centroid.y);
+  //Rotate Points so point 0 is left of centroid and solve for the bounding box
+  float xmin,xmax,ymin,ymax;
+  xmin = centroid.x;
+  xmax = centroid.x;
+  ymin = centroid.y;
+  ymax = centroid.y;
+  
+  float ang = atan2(centroid.y - points[0].y,
+		    centroid.x - points[0].x);
+
+  for(i = 0;i<numPoints;i++) {					       
+    float px = points[i].x;
+    float py = points[i].y;
+    points[i].x = (px - centroid.x)*cos(ang) - 
+                  (py - centroid.y)*sin(ang) + centroid.x;
+    points[i].y = (px - centroid.x)*sin(ang) + 
+                  (py - centroid.y)*cos(ang) + centroid.y;
+
+
+    if(points[i].x < xmin) xmin = points[i].x;
+    if(points[i].x > xmax) xmax = points[i].x; 
+    if(points[i].y < ymin) ymin = points[i].y;
+    if(points[i].y > ymax) ymax = points[i].y;
+  }
+
+  //Scale points to DOLLARSIZE, and translate to the origin
+  float w = xmax-xmin;
+  float h = ymax-ymin;
+
+  for(i=0;i<numPoints;i++) {
+    points[i].x = (points[i].x - centroid.x)*DOLLARSIZE/w;
+    points[i].y = (points[i].y - centroid.y)*DOLLARSIZE/h;
+  }  
+  return numPoints;
+}
+
+float dollarRecognize(SDL_DollarPath path,int *bestTempl,SDL_GestureTouch* touch) {
+	
+	SDL_FloatPoint points[DOLLARNPOINTS];
+	int numPoints = dollarNormalize(path,points);
+	//SDL_PrintPath(points);
+	int i;
+	
+	int bestDiff = 10000;
+	*bestTempl = -1;
+	for(i = 0;i < touch->numDollarTemplates;i++) {
+		int diff = bestDollarDifference(points,touch->dollarTemplate[i].path);
+		if(diff < bestDiff) {bestDiff = diff; *bestTempl = i;}
+	}
+	return bestDiff;
+}
+
+int SDL_GestureAddTouch(SDL_Touch* touch) {  
+  SDL_GestureTouch *gestureTouch = SDL_realloc(SDL_gestureTouch,
+					       (SDL_numGestureTouches + 1) *
+					       sizeof(SDL_GestureTouch));
+
+  if(!gestureTouch) {
+    SDL_OutOfMemory();
+    return -1;
+  }
+
+  SDL_gestureTouch = gestureTouch;
+
+  SDL_gestureTouch[SDL_numGestureTouches].res.x = touch->xres;
+  SDL_gestureTouch[SDL_numGestureTouches].res.y = touch->yres;
+  SDL_gestureTouch[SDL_numGestureTouches].numDownFingers = 0;
+
+  SDL_gestureTouch[SDL_numGestureTouches].res.x = touch->xres;
+  SDL_gestureTouch[SDL_numGestureTouches].id = touch->id;
+
+  SDL_gestureTouch[SDL_numGestureTouches].numDollarTemplates = 0;
+
+  SDL_gestureTouch[SDL_numGestureTouches].recording = SDL_FALSE;
+
+  SDL_numGestureTouches++;
+  return 0;
+}
+
+int SDL_GestureRemoveTouch(SDL_TouchID id) {
+  int i;
+  for(i = 0;i < SDL_numGestureTouches; i++) {
+    if(SDL_gestureTouch[i].id == id) {
+      SDL_numGestureTouches--;
+      SDL_gestureTouch[i] = SDL_gestureTouch[SDL_numGestureTouches];
+      return 1;
+    }
+  }
+  return -1;
+}
+
+
+SDL_GestureTouch * SDL_GetGestureTouch(SDL_TouchID id) {
+  int i;
+  for(i = 0;i < SDL_numGestureTouches; i++) {
+    //printf("%i ?= %i\n",SDL_gestureTouch[i].id,id);
+    if(SDL_gestureTouch[i].id == id) return &SDL_gestureTouch[i];
+  }
+  return NULL;
+}
+
+int SDL_SendGestureMulti(SDL_GestureTouch* touch,float dTheta,float dDist) {
+  SDL_Event event;
+  event.mgesture.type = SDL_MULTIGESTURE;
+  event.mgesture.touchId = touch->id;
+  event.mgesture.x = touch->centroid.x;
+  event.mgesture.y = touch->centroid.y;
+  event.mgesture.dTheta = dTheta;
+  event.mgesture.dDist = dDist;  
+  event.mgesture.numFingers = touch->numDownFingers;
+  return SDL_PushEvent(&event) > 0;
+}
+
+int SDL_SendGestureDollar(SDL_GestureTouch* touch,
+			  SDL_GestureID gestureId,float error) {
+  SDL_Event event;
+  event.dgesture.type = SDL_DOLLARGESTURE;
+  event.dgesture.touchId = touch->id;
+  /*
+    //TODO: Add this to give location of gesture?
+  event.mgesture.x = touch->centroid.x;
+  event.mgesture.y = touch->centroid.y;
+  */
+  event.dgesture.gestureId = gestureId;
+  event.dgesture.error = error;  
+  //A finger came up to trigger this event.
+  event.dgesture.numFingers = touch->numDownFingers + 1; 
+  return SDL_PushEvent(&event) > 0;
+}
+
+
+int SDL_SendDollarRecord(SDL_GestureTouch* touch,SDL_GestureID gestureId) {
+  SDL_Event event;
+  event.dgesture.type = SDL_DOLLARRECORD;
+  event.dgesture.touchId = touch->id;
+  event.dgesture.gestureId = gestureId;
+  return SDL_PushEvent(&event) > 0;
+}
+
+
+void SDL_GestureProcessEvent(SDL_Event* event)
+{
+  if(event->type == SDL_FINGERMOTION || 
+     event->type == SDL_FINGERDOWN ||
+     event->type == SDL_FINGERUP) {
+    SDL_GestureTouch* inTouch = SDL_GetGestureTouch(event->tfinger.touchId);
+    
+    //Shouldn't be possible
+    if(inTouch == NULL) return;
+    
+    //printf("@ (%i,%i) with res: (%i,%i)\n",(int)event->tfinger.x,
+    //	   (int)event->tfinger.y,
+    //   (int)inTouch->res.x,(int)inTouch->res.y);
+
+    
+    float x = ((float)event->tfinger.x)/(float)inTouch->res.x;
+    float y = ((float)event->tfinger.y)/(float)inTouch->res.y;   
+
+
+    //Finger Up
+    if(event->type == SDL_FINGERUP) {
+      inTouch->numDownFingers--;
+      
+#ifdef ENABLE_DOLLAR
+      if(inTouch->recording) {
+	inTouch->recording = SDL_FALSE;
+	SDL_FloatPoint path[DOLLARNPOINTS];
+	dollarNormalize(inTouch->dollarPath,path);
+	//SDL_PrintPath(path);
+	int index;
+	if(recordAll) {
+	  index = SDL_AddDollarGesture(NULL,path);
+	  int i;
+	  for(i = 0;i < SDL_numGestureTouches; i++)
+	    SDL_gestureTouch[i].recording = SDL_FALSE;
+	}
+	else {
+	  index = SDL_AddDollarGesture(inTouch,path);
+	}
+	
+	if(index >= 0) {
+	  SDL_SendDollarRecord(inTouch,inTouch->dollarTemplate[index].hash);
+	}
+	else {
+	  SDL_SendDollarRecord(inTouch,-1);
+	}
+      }
+      else {	
+	int bestTempl;
+	float error;
+	error = dollarRecognize(inTouch->dollarPath,
+				&bestTempl,inTouch);
+	if(bestTempl >= 0){
+	  //Send Event
+	  unsigned long gestureId = inTouch->dollarTemplate[bestTempl].hash;
+	  SDL_SendGestureDollar(inTouch,gestureId,error);
+	  //printf ("%s\n",);("Dollar error: %f\n",error);
+	}
+      }
+#endif 
+      //inTouch->gestureLast[j] = inTouch->gestureLast[inTouch->numDownFingers];
+      if(inTouch->numDownFingers > 0) {
+	inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers+1)-
+			       x)/inTouch->numDownFingers;
+	inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers+1)-
+			       y)/inTouch->numDownFingers;
+      }
+    }
+    else if(event->type == SDL_FINGERMOTION) {
+      float dx = ((float)event->tfinger.dx)/(float)inTouch->res.x;
+      float dy = ((float)event->tfinger.dy)/(float)inTouch->res.y;
+      //printf("dx,dy: (%f,%f)\n",dx,dy); 
+#ifdef ENABLE_DOLLAR
+      SDL_DollarPath* path = &inTouch->dollarPath;
+      if(path->numPoints < MAXPATHSIZE) {
+	path->p[path->numPoints].x = inTouch->centroid.x;
+	path->p[path->numPoints].y = inTouch->centroid.y;
+	float pathDx = 
+	  (path->p[path->numPoints].x-path->p[path->numPoints-1].x);
+	float pathDy = 
+	  (path->p[path->numPoints].y-path->p[path->numPoints-1].y);
+	path->length += sqrt(pathDx*pathDx + pathDy*pathDy);
+	path->numPoints++;
+      }
+#endif
+      SDL_FloatPoint lastP;
+      lastP.x = x - dx;
+      lastP.y = y - dy;
+      SDL_FloatPoint lastCentroid;
+      lastCentroid = inTouch->centroid;
+      
+      inTouch->centroid.x += dx/inTouch->numDownFingers;
+      inTouch->centroid.y += dy/inTouch->numDownFingers;
+      //printf("Centrid : (%f,%f)\n",inTouch->centroid.x,inTouch->centroid.y);
+      if(inTouch->numDownFingers > 1) {
+	SDL_FloatPoint lv; //Vector from centroid to last x,y position
+	SDL_FloatPoint v; //Vector from centroid to current x,y position
+	//lv = inTouch->gestureLast[j].cv;
+	lv.x = lastP.x - lastCentroid.x;
+	lv.y = lastP.y - lastCentroid.y;
+	float lDist = sqrt(lv.x*lv.x + lv.y*lv.y);
+	//printf("lDist = %f\n",lDist);
+	v.x = x - inTouch->centroid.x;
+	v.y = y - inTouch->centroid.y;
+	//inTouch->gestureLast[j].cv = v;
+	float Dist = sqrt(v.x*v.x+v.y*v.y);
+	// cos(dTheta) = (v . lv)/(|v| * |lv|)
+	
+	//Normalize Vectors to simplify angle calculation
+	lv.x/=lDist;
+	lv.y/=lDist;
+	v.x/=Dist;
+	v.y/=Dist;
+	float dtheta = atan2(lv.x*v.y - lv.y*v.x,lv.x*v.x + lv.y*v.y);
+	
+	float dDist = (Dist - lDist);
+	if(lDist == 0) {dDist = 0;dtheta = 0;} //To avoid impossible values
+	
+	//inTouch->gestureLast[j].dDist = dDist;
+	//inTouch->gestureLast[j].dtheta = dtheta;
+	
+	//printf("dDist = %f, dTheta = %f\n",dDist,dtheta);
+	//gdtheta = gdtheta*.9 + dtheta*.1;
+	//gdDist  =  gdDist*.9 +  dDist*.1
+	//knob.r += dDist/numDownFingers;
+	//knob.ang += dtheta;
+	//printf("thetaSum = %f, distSum = %f\n",gdtheta,gdDist);
+	//printf("id: %i dTheta = %f, dDist = %f\n",j,dtheta,dDist);
+	SDL_SendGestureMulti(inTouch,dtheta,dDist);
+      }
+      else {
+	//inTouch->gestureLast[j].dDist = 0;
+	//inTouch->gestureLast[j].dtheta = 0;
+	//inTouch->gestureLast[j].cv.x = 0;
+	//inTouch->gestureLast[j].cv.y = 0;
+      }
+      //inTouch->gestureLast[j].f.p.x = x;
+      //inTouch->gestureLast[j].f.p.y = y;
+      //break;
+      //pressure?
+    }
+    
+    if(event->type == SDL_FINGERDOWN) {
+
+      inTouch->numDownFingers++;
+      inTouch->centroid.x = (inTouch->centroid.x*(inTouch->numDownFingers - 1)+ 
+			     x)/inTouch->numDownFingers;
+      inTouch->centroid.y = (inTouch->centroid.y*(inTouch->numDownFingers - 1)+
+			     y)/inTouch->numDownFingers;
+      //printf("Finger Down: (%f,%f). Centroid: (%f,%f\n",x,y,
+      //     inTouch->centroid.x,inTouch->centroid.y);
+
+#ifdef ENABLE_DOLLAR
+      inTouch->dollarPath.length = 0;
+      inTouch->dollarPath.p[0].x = x;
+      inTouch->dollarPath.p[0].y = y;
+      inTouch->dollarPath.numPoints = 1;
+#endif
+    }
+  }
+}
+
+  /* vi: set ts=4 sw=4 expandtab: */
+  
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/events/SDL_gesture_c.h	Sun Aug 22 12:07:55 2010 -0700
@@ -0,0 +1,35 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997-2010 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_gesture_c_h
+#define _SDL_gesture_c_h
+
+extern void SDL_GestureProcessEvent(SDL_Event* event);
+
+extern int SDL_RecordGesture(SDL_TouchID touchId);
+
+extern int SDL_GestureAddTouch(SDL_Touch* touch);
+
+#endif /* _SDL_gesture_c_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/events/SDL_touch.c	Sun Aug 22 12:07:55 2010 -0700
@@ -0,0 +1,555 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997-2010 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+/* General touch handling code for SDL */
+
+#include "SDL_events.h"
+#include "SDL_events_c.h"
+#include "../video/SDL_sysvideo.h"
+
+#include <stdio.h>
+
+
+static int SDL_num_touch = 0;
+static SDL_Touch **SDL_touchPads = NULL;
+
+
+/* Public functions */
+int
+SDL_TouchInit(void)
+{
+  return (0);
+}
+
+SDL_Touch *
+SDL_GetTouch(SDL_TouchID id)
+{
+    int index = SDL_GetTouchIndexId(id);
+    if (index < 0 || index >= SDL_num_touch) {
+        return NULL;
+    }
+    return SDL_touchPads[index];
+}
+
+SDL_Touch *
+SDL_GetTouchIndex(int index)
+{
+    if (index < 0 || index >= SDL_num_touch) {
+        return NULL;
+    }
+    return SDL_touchPads[index];
+}
+
+int
+SDL_GetFingerIndexId(SDL_Touch* touch,SDL_FingerID fingerid)
+{
+    int i;
+    for(i = 0;i < touch->num_fingers;i++)
+	if(touch->fingers[i]->id == fingerid)
+	    return i;
+    return -1;
+}
+
+
+SDL_Finger *
+SDL_GetFinger(SDL_Touch* touch,SDL_FingerID id)
+{
+    int index = SDL_GetFingerIndexId(touch,id);
+    if(index < 0 || index >= touch->num_fingers)
+	return NULL;
+    return touch->fingers[index];
+}
+
+
+int
+SDL_GetTouchIndexId(SDL_TouchID id)
+{
+    int index;
+    SDL_Touch *touch;
+
+    for (index = 0; index < SDL_num_touch; ++index) {
+        touch = SDL_touchPads[index];
+        if (touch->id == id) {
+            return index;
+        }
+    }
+    return -1;
+}
+
+int
+SDL_AddTouch(const SDL_Touch * touch, char *name)
+{
+    SDL_Touch **touchPads;
+    int index,length;
+
+    if (SDL_GetTouchIndexId(touch->id) != -1) {
+        SDL_SetError("Touch ID already in use");
+    }
+
+    /* Add the touch to the list of touch */
+    touchPads = (SDL_Touch **) SDL_realloc(SDL_touchPads,
+                                      (SDL_num_touch + 1) * sizeof(*touch));
+    if (!touchPads) {
+        SDL_OutOfMemory();
+        return -1;
+    }
+
+    SDL_touchPads = touchPads;
+    index = SDL_num_touch++;
+
+    SDL_touchPads[index] = (SDL_Touch *) SDL_malloc(sizeof(*SDL_touchPads[index]));
+    if (!SDL_touchPads[index]) {
+        SDL_OutOfMemory();
+        return -1;
+    }
+    *SDL_touchPads[index] = *touch;
+
+    /* we're setting the touch properties */
+    length = 0;
+    length = SDL_strlen(name);
+    SDL_touchPads[index]->focus = 0;
+    SDL_touchPads[index]->name = SDL_malloc((length + 2) * sizeof(char));
+    SDL_strlcpy(SDL_touchPads[index]->name, name, length + 1);   
+
+    SDL_touchPads[index]->num_fingers = 0;
+    SDL_touchPads[index]->max_fingers = 1;
+    SDL_touchPads[index]->fingers = (SDL_Finger **) SDL_malloc(sizeof(SDL_Finger*));
+    SDL_touchPads[index]->fingers[0] = NULL;
+    SDL_touchPads[index]->buttonstate = 0;
+    SDL_touchPads[index]->relative_mode = SDL_FALSE;
+    SDL_touchPads[index]->flush_motion = SDL_FALSE;
+    
+    SDL_touchPads[index]->xres = (1<<(16-1));
+    SDL_touchPads[index]->yres = (1<<(16-1));
+    //Do I want this here? Probably
+    SDL_GestureAddTouch(SDL_touchPads[index]);
+
+    return index;
+}
+
+void
+SDL_DelTouch(SDL_TouchID id)
+{
+    int index = SDL_GetTouchIndexId(id);
+    SDL_Touch *touch = SDL_GetTouch(id);
+
+    if (!touch) {
+        return;
+    }
+
+    
+    SDL_free(touch->name);
+ 
+    if (touch->FreeTouch) {
+        touch->FreeTouch(touch);
+    }
+    SDL_free(touch);
+
+    SDL_num_touch--;
+    SDL_touchPads[index] = SDL_touchPads[SDL_num_touch];
+}
+
+void
+SDL_TouchQuit(void)
+{
+    int i;
+
+    for (i = SDL_num_touch-1; i > 0 ; --i) {
+        SDL_DelTouch(i);
+    }
+    SDL_num_touch = 0;
+
+    if (SDL_touchPads) {
+        SDL_free(SDL_touchPads);
+        SDL_touchPads = NULL;
+    }
+}
+
+int
+SDL_GetNumTouch(void)
+{
+    return SDL_num_touch;
+}
+SDL_Window *
+SDL_GetTouchFocusWindow(SDL_TouchID id)
+{
+    SDL_Touch *touch = SDL_GetTouch(id);
+
+    if (!touch) {
+        return 0;
+    }
+    return touch->focus;
+}
+
+void
+SDL_SetTouchFocus(SDL_TouchID id, SDL_Window * window)
+{
+    int index = SDL_GetTouchIndexId(id);
+    SDL_Touch *touch = SDL_GetTouch(id);
+    int i;
+    SDL_bool focus;
+
+    if (!touch || (touch->focus == window)) {
+        return;
+    }
+
+    /* See if the current window has lost focus */
+    if (touch->focus) {
+        focus = SDL_FALSE;
+        for (i = 0; i < SDL_num_touch; ++i) {
+            SDL_Touch *check;
+            if (i != index) {
+                check = SDL_touchPads[i];
+                if (check && check->focus == touch->focus) {
+                    focus = SDL_TRUE;
+                    break;
+                }
+            }
+        }
+        if (!focus) {
+            SDL_SendWindowEvent(touch->focus, SDL_WINDOWEVENT_LEAVE, 0, 0);
+        }
+    }
+
+    touch->focus = window;
+
+    if (touch->focus) {
+        focus = SDL_FALSE;
+        for (i = 0; i < SDL_num_touch; ++i) {
+            SDL_Touch *check;
+            if (i != index) {
+                check = SDL_touchPads[i];
+                if (check && check->focus == touch->focus) {
+                    focus = SDL_TRUE;
+                    break;
+                }
+            }
+        }
+        if (!focus) {
+            SDL_SendWindowEvent(touch->focus, SDL_WINDOWEVENT_ENTER, 0, 0);
+        }
+    }
+}
+
+int 
+SDL_AddFinger(SDL_Touch* touch,SDL_Finger *finger)
+{
+    int index;
+    SDL_Finger **fingers;
+    //printf("Adding Finger...\n");
+    if (SDL_GetFingerIndexId(touch,finger->id) != -1) {
+        SDL_SetError("Finger ID already in use");
+	}
+
+    /* Add the touch to the list of touch */
+    if(touch->num_fingers  >= touch->max_fingers){
+		//printf("Making room for it!\n");
+		fingers = (SDL_Finger **) SDL_realloc(touch->fingers,
+  						   (touch->num_fingers + 1) * sizeof(SDL_Finger *));
+		touch->max_fingers = touch->num_fingers+1;
+		if (!fingers) {
+			SDL_OutOfMemory();
+			return -1;
+		} else {
+			touch->max_fingers = touch->num_fingers+1;
+			touch->fingers = fingers;
+		}
+	}
+
+    index = touch->num_fingers;
+    //printf("Max_Fingers: %i Index: %i\n",touch->max_fingers,index);
+
+    touch->fingers[index] = (SDL_Finger *) SDL_malloc(sizeof(SDL_Finger));
+    if (!touch->fingers[index]) {
+        SDL_OutOfMemory();
+        return -1;
+    }
+    *(touch->fingers[index]) = *finger;
+    touch->num_fingers++;
+
+    return index;
+}
+
+int
+SDL_DelFinger(SDL_Touch* touch,SDL_FingerID fingerid)
+{
+    int index = SDL_GetFingerIndexId(touch,fingerid);
+    SDL_Finger* finger = SDL_GetFinger(touch,fingerid);
+
+    if (!finger) {
+        return -1;
+    }
+ 
+
+    SDL_free(finger);
+    touch->num_fingers--;
+    touch->fingers[index] = touch->fingers[touch->num_fingers];
+    return 0;
+}
+
+
+int
+SDL_SendFingerDown(SDL_TouchID id, SDL_FingerID fingerid, SDL_bool down, 
+		   float xin, float yin, float pressurein)
+{
+    int posted;
+    SDL_Touch* touch = SDL_GetTouch(id);
+
+    if(!touch) {
+      return SDL_TouchNotFoundError(id);
+    }
+
+    
+    //scale to Integer coordinates
+    Uint16 x = (xin+touch->x_min)*(touch->xres)/(touch->native_xres);
+    Uint16 y = (yin+touch->y_min)*(touch->yres)/(touch->native_yres);
+    Uint16 pressure = (yin+touch->pressure_min)*(touch->pressureres)/(touch->native_pressureres);
+    
+    SDL_Finger *finger = SDL_GetFinger(touch,fingerid);
+    if(down) {
+	if(finger == NULL) {
+	    SDL_Finger nf;
+	    nf.id = fingerid;
+	    nf.x = x;
+	    nf.y = y;
+	    nf.pressure = pressure;
+	    nf.xdelta = 0;
+	    nf.ydelta = 0;
+	    nf.last_x = x;
+	    nf.last_y = y;
+	    nf.last_pressure = pressure;
+	    nf.down = SDL_FALSE;
+	    if(SDL_AddFinger(touch,&nf) < 0) return 0;
+	    finger = SDL_GetFinger(touch,fingerid);
+	}
+	else if(finger->down) return 0;
+	if(xin < touch->x_min || yin < touch->y_min) return 0; //should defer if only a partial input
+	posted = 0;
+	if (SDL_GetEventState(SDL_FINGERDOWN) == SDL_ENABLE) {
+	    SDL_Event event;
+	    event.tfinger.type = SDL_FINGERDOWN;
+	    event.tfinger.touchId = id;
+	    event.tfinger.x = x;
+	    event.tfinger.y = y;
+	    event.tfinger.pressure = pressure;
+	    event.tfinger.state = touch->buttonstate;
+	    event.tfinger.windowID = touch->focus ? touch->focus->id : 0;
+	    event.tfinger.fingerId = fingerid;
+	    posted = (SDL_PushEvent(&event) > 0);
+	}
+	if(posted) finger->down = SDL_TRUE;
+	return posted;
+    }
+    else {
+        if(finger == NULL) {printf("Finger not found...\n");return 0;}      
+	posted = 0;
+	if (SDL_GetEventState(SDL_FINGERUP) == SDL_ENABLE) {
+	    SDL_Event event;
+	    event.tfinger.type = SDL_FINGERUP;
+	    event.tfinger.touchId =  id;
+	    event.tfinger.state = touch->buttonstate;
+	    event.tfinger.windowID = touch->focus ? touch->focus->id : 0;
+	    event.tfinger.fingerId = fingerid;
+	    //I don't trust the coordinates passed on fingerUp
+	    event.tfinger.x = finger->x; 
+	    event.tfinger.y = finger->y;
+	    event.tfinger.dx = 0;
+	    event.tfinger.dy = 0;
+
+	    if(SDL_DelFinger(touch,fingerid) < 0) return 0;
+	    posted = (SDL_PushEvent(&event) > 0);
+	}	
+	return posted;
+    }
+}
+
+int
+SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid, int relative, 
+		    float xin, float yin, float pressurein)
+{
+    int index = SDL_GetTouchIndexId(id);
+    SDL_Touch *touch = SDL_GetTouch(id);
+    SDL_Finger *finger = SDL_GetFinger(touch,fingerid);
+    int posted;
+    Sint16 xrel, yrel;
+    float x_max = 0, y_max = 0;
+    
+    if (!touch) {
+      return SDL_TouchNotFoundError(id);
+    }
+
+    //scale to Integer coordinates
+    Uint16 x = (xin+touch->x_min)*(touch->xres)/(touch->native_xres);
+    Uint16 y = (yin+touch->y_min)*(touch->yres)/(touch->native_yres);
+    Uint16 pressure = (yin+touch->pressure_min)*(touch->pressureres)/(touch->native_pressureres);
+    if(touch->flush_motion) {
+	return 0;
+    }
+    
+    if(finger == NULL || !finger->down) {
+	return SDL_SendFingerDown(id,fingerid,SDL_TRUE,xin,yin,pressurein);	
+    } else {
+	/* the relative motion is calculated regarding the last position */
+	if (relative) {
+	    xrel = x;
+	    yrel = y;
+	    x = (finger->last_x + x);
+	    y = (finger->last_y + y);
+	} else {
+	    if(xin < touch->x_min) x = finger->last_x; /*If movement is only in one axis,*/
+	    if(yin < touch->y_min) y = finger->last_y; /*The other is marked as -1*/
+	    if(pressurein < touch->pressure_min) pressure = finger->last_pressure;
+	    xrel = x - finger->last_x;
+	    yrel = y - finger->last_y;
+	    //printf("xrel,yrel (%i,%i)\n",(int)xrel,(int)yrel);
+	}
+	
+	/* Drop events that don't change state */
+	if (!xrel && !yrel) {
+#if 0
+	    printf("Touch event didn't change state - dropped!\n");
+#endif
+	    return 0;
+	}
+	
+	/* Update internal touch coordinates */
+	
+	finger->x = x;
+	finger->y = y;
+	
+	/*Should scale to window? Normalize? Maintain Aspect?*/
+	//SDL_GetWindowSize(touch->focus, &x_max, &y_max);
+	
+	/* make sure that the pointers find themselves inside the windows */
+	/* only check if touch->xmax is set ! */
+	/*
+	  if (x_max && touch->x > x_max) {
+	  touch->x = x_max;
+	  } else if (touch->x < 0) {
+	  touch->x = 0;
+	  }
+	  
+	  if (y_max && touch->y > y_max) {
+	  touch->y = y_max;
+	  } else if (touch->y < 0) {
+	  touch->y = 0;
+	  }
+	*/
+	finger->xdelta = xrel;
+	finger->ydelta = yrel;
+	finger->pressure = pressure;
+	
+	
+	
+	/* Post the event, if desired */
+	posted = 0;
+	if (SDL_GetEventState(SDL_FINGERMOTION) == SDL_ENABLE) {
+	    SDL_Event event;
+	    event.tfinger.type = SDL_FINGERMOTION;
+	    event.tfinger.touchId = id;
+	    event.tfinger.fingerId = fingerid;
+	    event.tfinger.x = x;
+	    event.tfinger.y = y;
+	    event.tfinger.dx = xrel;
+	    event.tfinger.dy = yrel;	    
+		
+	    event.tfinger.pressure = pressure;
+	    event.tfinger.state = touch->buttonstate;
+	    event.tfinger.windowID = touch->focus ? touch->focus->id : 0;
+	    posted = (SDL_PushEvent(&event) > 0);
+	}
+	finger->last_x = finger->x;
+	finger->last_y = finger->y;
+	finger->last_pressure = finger->pressure;
+	return posted;
+    }
+}
+int
+SDL_SendTouchButton(SDL_TouchID id, Uint8 state, Uint8 button)
+{
+    SDL_Touch *touch = SDL_GetTouch(id);
+    int posted;
+    Uint32 type;
+
+    
+    if (!touch) {
+      return SDL_TouchNotFoundError(id);
+    }
+
+    /* Figure out which event to perform */
+    switch (state) {
+    case SDL_PRESSED:
+        if (touch->buttonstate & SDL_BUTTON(button)) {
+            /* Ignore this event, no state change */
+            return 0;
+        }
+        type = SDL_TOUCHBUTTONDOWN;
+        touch->buttonstate |= SDL_BUTTON(button);
+        break;
+    case SDL_RELEASED:
+        if (!(touch->buttonstate & SDL_BUTTON(button))) {
+            /* Ignore this event, no state change */
+            return 0;
+        }
+        type = SDL_TOUCHBUTTONUP;
+        touch->buttonstate &= ~SDL_BUTTON(button);
+        break;
+    default:
+        /* Invalid state -- bail */
+        return 0;
+    }
+
+    /* Post the event, if desired */
+    posted = 0;
+    if (SDL_GetEventState(type) == SDL_ENABLE) {
+        SDL_Event event;
+        event.type = type;
+        event.tbutton.touchId = touch->id;
+        event.tbutton.state = state;
+        event.tbutton.button = button;
+        event.tbutton.windowID = touch->focus ? touch->focus->id : 0;
+        posted = (SDL_PushEvent(&event) > 0);
+    }
+    return posted;
+}
+
+char *
+SDL_GetTouchName(SDL_TouchID id)
+{
+    SDL_Touch *touch = SDL_GetTouch(id);
+    if (!touch) {
+        return NULL;
+    }
+    return touch->name;
+}
+
+int SDL_TouchNotFoundError(SDL_TouchID id) {
+  printf("ERROR: Cannot send touch on non-existent device with id: %li make sure SDL_AddTouch has been called\n",id);
+  printf("ERROR: There are %i touches installed with Id's:\n",SDL_num_touch);
+  int i;
+  for(i=0;i < SDL_num_touch;i++) {
+    printf("ERROR: %li\n",SDL_touchPads[i]->id);
+  }
+  return 0;
+}
+/* vi: set ts=4 sw=4 expandtab: */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/events/SDL_touch_c.h	Sun Aug 22 12:07:55 2010 -0700
@@ -0,0 +1,79 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997-2010 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+#include "SDL_config.h"
+#include "../../include/SDL_touch.h"
+
+#ifndef _SDL_touch_c_h
+#define _SDL_touch_c_h
+
+
+
+/* Initialize the touch subsystem */
+extern int SDL_TouchInit(void);
+
+/*Get the touch at an index */
+extern SDL_Touch *SDL_GetTouchIndex(int index);
+
+/* Get the touch with id = id */
+extern SDL_Touch *SDL_GetTouch(SDL_TouchID id);
+
+/*Get the finger at an index */
+extern SDL_Finger *SDL_GetFingerIndex(SDL_Touch *touch, int index);
+
+/* Get the finger with id = id */
+extern SDL_Finger *SDL_GetFinger(SDL_Touch *touch,SDL_FingerID id);
+
+
+/* Add a touch, possibly reattaching at a particular index (or -1),
+   returning the index of the touch, or -1 if there was an error. */
+extern int SDL_AddTouch(const SDL_Touch * touch, char *name);
+                     
+
+/* Remove a touch at an index, clearing the slot for later */
+extern void SDL_DelTouch(SDL_TouchID id);
+
+/* Set the touch focus window */
+extern void SDL_SetTouchFocus(SDL_TouchID id, SDL_Window * window);
+
+/* Send a touch motion event for a touch */
+extern int SDL_SendTouchMotion(SDL_TouchID id, SDL_FingerID fingerid,
+			       int relative, float x, float y, float z);
+
+/* Send a touch down/up event for a touch */
+extern int SDL_SendFingerDown(SDL_TouchID id, SDL_FingerID fingerid, 
+			      SDL_bool down, float x, float y, float pressure);
+
+/* Send a touch button event for a touch */
+extern int SDL_SendTouchButton(SDL_TouchID id, Uint8 state, Uint8 button);
+
+/* Shutdown the touch subsystem */
+extern void SDL_TouchQuit(void);
+
+/* Get the index of a touch device */
+extern int SDL_GetTouchIndexId(SDL_TouchID id);
+
+/* Print a debug message for a nonexistent touch */
+extern int SDL_TouchNotFoundError(SDL_TouchID id);
+
+#endif /* _SDL_touch_c_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/cocoa/SDL_cocoaevents.m	Sun Aug 22 11:56:07 2010 -0700
+++ b/src/video/cocoa/SDL_cocoaevents.m	Sun Aug 22 12:07:55 2010 -0700
@@ -192,6 +192,9 @@
         if ( event == nil ) {
             break;
         }
+		
+	//printf("Type: %i, Subtype: %i\n",[event type],[event subtype]);
+		
         switch ([event type]) {
         case NSLeftMouseDown:
         case NSOtherMouseDown:
@@ -203,6 +206,7 @@
         case NSRightMouseDragged:
         case NSOtherMouseDragged: /* usually middle mouse dragged */
         case NSMouseMoved:
+	  printf("Mouse Type: %i, Subtype: %i\n",[event type],[event subtype]);
             Cocoa_HandleMouseEvent(_this, event);
             /* Pass through to NSApp to make sure everything stays in sync */
             [NSApp sendEvent:event];
@@ -217,6 +221,8 @@
             if (([event modifierFlags] & NSCommandKeyMask) || [event type] == NSFlagsChanged)
                [NSApp sendEvent: event];
             break;
+	case NSTabletPoint:
+	  printf("Tablet Event Received\n");
         default:
             [NSApp sendEvent:event];
             break;
--- a/src/video/cocoa/SDL_cocoawindow.h	Sun Aug 22 11:56:07 2010 -0700
+++ b/src/video/cocoa/SDL_cocoawindow.h	Sun Aug 22 12:07:55 2010 -0700
@@ -64,6 +64,20 @@
 -(void) rightMouseDragged:(NSEvent *) theEvent;
 -(void) otherMouseDragged:(NSEvent *) theEvent;
 -(void) scrollWheel:(NSEvent *) theEvent;
+-(void) touchesBeganWithEvent:(NSEvent *) theEvent;
+-(void) touchesMovedWithEvent:(NSEvent *) theEvent;
+-(void) touchesEndedWithEvent:(NSEvent *) theEvent;
+-(void) touchesCancelledWithEvent:(NSEvent *) theEvent;
+
+/* Touch event handling */
+typedef enum {
+    COCOA_TOUCH_DOWN,
+    COCOA_TOUCH_UP,
+    COCOA_TOUCH_MOVE,
+    COCOA_TOUCH_CANCELLED
+} cocoaTouchType;
+-(void) handleTouches:(cocoaTouchType)type withEvent:(NSEvent*) event;
+
 @end
 /* *INDENT-ON* */
 
--- a/src/video/cocoa/SDL_cocoawindow.m	Sun Aug 22 11:56:07 2010 -0700
+++ b/src/video/cocoa/SDL_cocoawindow.m	Sun Aug 22 12:07:55 2010 -0700
@@ -25,8 +25,8 @@
 #include "../SDL_sysvideo.h"
 #include "../../events/SDL_keyboard_c.h"
 #include "../../events/SDL_mouse_c.h"
+#include "../../events/SDL_touch_c.h"
 #include "../../events/SDL_windowevents_c.h"
-
 #include "SDL_cocoavideo.h"
 
 static __inline__ void ConvertNSRect(NSRect *r)
@@ -60,6 +60,7 @@
     [center addObserver:self selector:@selector(windowDidUnhide:) name:NSApplicationDidUnhideNotification object:NSApp];
 
     [_data->nswindow setAcceptsMouseMovedEvents:YES];
+    [[_data->nswindow contentView] setAcceptsTouchEvents:YES];
 }
 
 - (void)close
@@ -268,6 +269,91 @@
     SDL_SendMouseWheel(_data->window, (int)x, (int)y);
 }
 
+- (void)touchesBeganWithEvent:(NSEvent *) theEvent
+{
+    [self handleTouches:COCOA_TOUCH_DOWN withEvent:theEvent];
+}
+
+- (void)touchesMovedWithEvent:(NSEvent *) theEvent
+{
+    [self handleTouches:COCOA_TOUCH_MOVE withEvent:theEvent];
+}
+
+- (void)touchesEndedWithEvent:(NSEvent *) theEvent
+{
+    [self handleTouches:COCOA_TOUCH_UP withEvent:theEvent];
+}
+
+- (void)touchesCancelledWithEvent:(NSEvent *) theEvent
+{
+    [self handleTouches:COCOA_TOUCH_CANCELLED withEvent:theEvent];
+}
+
+- (void)handleTouches:(cocoaTouchType)type withEvent:(NSEvent *)event
+{
+    NSSet *touches = 0;
+    NSEnumerator *enumerator;
+    NSTouch *touch;
+
+    switch (type) {
+        case COCOA_TOUCH_DOWN:
+            touches = [event touchesMatchingPhase:NSTouchPhaseBegan inView:nil];
+            break;
+        case COCOA_TOUCH_UP:
+        case COCOA_TOUCH_CANCELLED:
+            touches = [event touchesMatchingPhase:NSTouchPhaseEnded inView:nil];
+            break;
+        case COCOA_TOUCH_MOVE:
+            touches = [event touchesMatchingPhase:NSTouchPhaseMoved inView:nil];
+            break;
+    }
+
+    enumerator = [touches objectEnumerator];
+    touch = (NSTouch*)[enumerator nextObject];
+    while (touch) {
+        SDL_TouchID touchId = (SDL_TouchID)[touch device];
+        if (!SDL_GetTouch(touchId)) {
+            SDL_Touch touch;
+
+            touch.id = touchId;
+            touch.x_min = 0;
+            touch.x_max = 1;
+            touch.native_xres = touch.x_max - touch.x_min;
+            touch.y_min = 0;
+            touch.y_max = 1;
+            touch.native_yres = touch.y_max - touch.y_min;
+            touch.pressure_min = 0;
+            touch.pressure_max = 1;
+            touch.native_pressureres = touch.pressure_max - touch.pressure_min;
+            
+            if (SDL_AddTouch(&touch, "") < 0) {
+                return;
+            }
+        } 
+
+        SDL_FingerID fingerId = (SDL_FingerID)[touch identity];
+        float x = [touch normalizedPosition].x;
+        float y = [touch normalizedPosition].y;
+	/* Make the origin the upper left instead of the lower left */
+	y = 1.0f - y;
+
+        switch (type) {
+        case COCOA_TOUCH_DOWN:
+            SDL_SendFingerDown(touchId, fingerId, SDL_TRUE, x, y, 1);
+            break;
+        case COCOA_TOUCH_UP:
+        case COCOA_TOUCH_CANCELLED:
+            SDL_SendFingerDown(touchId, fingerId, SDL_FALSE, x, y, 1);
+            break;
+        case COCOA_TOUCH_MOVE:
+            SDL_SendTouchMotion(touchId, fingerId, SDL_FALSE, x, y, 1);
+            break;
+        }
+        
+        touch = (NSTouch*)[enumerator nextObject];
+    }
+}
+
 @end
 
 @interface SDLWindow : NSWindow
--- a/src/video/uikit/SDL_uikitview.h	Sun Aug 22 11:56:07 2010 -0700
+++ b/src/video/uikit/SDL_uikitview.h	Sun Aug 22 12:07:55 2010 -0700
@@ -13,8 +13,7 @@
     Lesser General Public License for more details.
 
     You should have received a copy of the GNU Lesser General Public
-    License along with this library; if not, write to the Free Software
-    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+    License along with this library; if not, write to the Free Software    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
     Sam Lantinga
     slouken@libsdl.org
@@ -24,10 +23,11 @@
 #include "SDL_stdinc.h"
 #include "SDL_events.h"
 
-#if SDL_IPHONE_MULTIPLE_MICE
+#define IPHONE_TOUCH_EFFICIENT_DANGEROUS
+#define FIXED_MULTITOUCH
+
+#ifndef IPHONE_TOUCH_EFFICIENT_DANGEROUS
 #define MAX_SIMULTANEOUS_TOUCHES 5
-#else
-#define MAX_SIMULTANEOUS_TOUCHES 1
 #endif
 
 /* *INDENT-OFF* */
@@ -37,8 +37,11 @@
 @interface SDL_uikitview : UIView {
 #endif
 
-#if FIXME_MULTITOUCH
-	SDL_Mouse mice[MAX_SIMULTANEOUS_TOUCHES];
+#ifdef FIXED_MULTITOUCH
+	long touchId;
+#ifndef IPHONE_TOUCH_EFFICIENT_DANGEROUS
+	UITouch *finger[MAX_SIMULTANEOUS_TOUCHES];
+#endif
 #endif
 
 #if SDL_IPHONE_KEYBOARD
--- a/src/video/uikit/SDL_uikitview.m	Sun Aug 22 11:56:07 2010 -0700
+++ b/src/video/uikit/SDL_uikitview.m	Sun Aug 22 12:07:55 2010 -0700
@@ -24,6 +24,7 @@
 
 #include "../../events/SDL_keyboard_c.h"
 #include "../../events/SDL_mouse_c.h"
+#include "../../events/SDL_touch_c.h"
 
 #if SDL_IPHONE_KEYBOARD
 #import "keyinfotable.h"
@@ -48,16 +49,27 @@
 	[self initializeKeyboard];
 #endif	
 
-#if FIXME_MULTITOUCH
-	int i;
-	for (i=0; i<MAX_SIMULTANEOUS_TOUCHES; i++) {
-        mice[i].id = i;
-		mice[i].driverdata = NULL;
-		SDL_AddMouse(&mice[i], "Mouse", 0, 0, 1);
-	}
-	self.multipleTouchEnabled = YES;
+#ifdef FIXED_MULTITOUCH
+	SDL_Touch touch;
+	touch.id = 0; //TODO: Should be -1?
+
+	//touch.driverdata = SDL_malloc(sizeof(EventTouchData));
+	//EventTouchData* data = (EventTouchData*)(touch.driverdata);
+	
+	touch.x_min = 0;
+	touch.x_max = frame.size.width;
+	touch.native_xres = touch.x_max - touch.x_min;
+	touch.y_min = 0;
+	touch.y_max = frame.size.height;
+	touch.native_yres = touch.y_max - touch.y_min;
+	touch.pressure_min = 0;
+	touch.pressure_max = 1;
+	touch.native_pressureres = touch.pressure_max - touch.pressure_min;
+
+
+	touchId = SDL_AddTouch(&touch, "IPHONE SCREEN");
 #endif
-			
+
 	return self;
 
 }
@@ -67,48 +79,8 @@
 	NSEnumerator *enumerator = [touches objectEnumerator];
 	UITouch *touch = (UITouch*)[enumerator nextObject];
 	
-#if FIXME_MULTITOUCH
-	/* associate touches with mice, so long as we have slots */
-	int i;
-	int found = 0;
-	for(i=0; touch && i < MAX_SIMULTANEOUS_TOUCHES; i++) {
+	//NSLog("Click");
 	
-		/* check if this mouse is already tracking a touch */
-		if (mice[i].driverdata != NULL) {
-			continue;
-		}
-		/*	
-			mouse not associated with anything right now,
-			associate the touch with this mouse
-		*/
-		found = 1;
-		
-		/* save old mouse so we can switch back */
-		int oldMouse = SDL_SelectMouse(-1);
-		
-		/* select this slot's mouse */
-		SDL_SelectMouse(i);
-		CGPoint locationInView = [touch locationInView: self];
-		
-		/* set driver data to touch object, we'll use touch object later */
-		mice[i].driverdata = [touch retain];
-		
-		/* send moved event */
-		SDL_SendMouseMotion(i, 0, locationInView.x, locationInView.y, 0);
-		
-		/* send mouse down event */
-		SDL_SendMouseButton(i, SDL_PRESSED, SDL_BUTTON_LEFT);
-		
-		/* re-calibrate relative mouse motion */
-		SDL_GetRelativeMouseState(i, NULL, NULL);
-		
-		/* switch back to our old mouse */
-		SDL_SelectMouse(oldMouse);
-		
-		/* grab next touch */
-		touch = (UITouch*)[enumerator nextObject]; 
-	}
-#else
 	if (touch) {
 		CGPoint locationInView = [touch locationInView: self];
 			
@@ -118,6 +90,37 @@
 		/* send mouse down event */
 		SDL_SendMouseButton(NULL, SDL_PRESSED, SDL_BUTTON_LEFT);
 	}
+
+#ifdef FIXED_MULTITOUCH
+	while(touch) {
+	  CGPoint locationInView = [touch locationInView: self];
+
+
+#ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
+	  //FIXME: TODO: Using touch as the fingerId is potentially dangerous
+	  //It is also much more efficient than storing the UITouch pointer
+	  //and comparing it to the incoming event.
+	  SDL_SendFingerDown(touchId,(long)touch,
+			     SDL_TRUE,locationInView.x,locationInView.y,
+			     1);
+#else
+	  int i;
+	  for(i = 0;i < MAX_SIMULTANEOUS_TOUCHES;i++) {
+	    if(finger[i] == NULL) {
+	      finger[i] = touch;
+	      SDL_SendFingerDown(touchId,i,
+				 SDL_TRUE,locationInView.x,locationInView.y,
+				 1);
+	      break;
+	    }
+	  }
+#endif
+	  
+
+	  
+
+	  touch = (UITouch*)[enumerator nextObject]; 
+	}
 #endif
 }
 
@@ -126,30 +129,34 @@
 	NSEnumerator *enumerator = [touches objectEnumerator];
 	UITouch *touch = (UITouch*)[enumerator nextObject];
 	
-#if FIXME_MULTITOUCH
-	while(touch) {
-		/* search for the mouse slot associated with this touch */
-		int i, found = NO;
-		for (i=0; i<MAX_SIMULTANEOUS_TOUCHES && !found; i++) {
-			if (mice[i].driverdata == touch) {
-				/* found the mouse associate with the touch */
-				[(UITouch*)(mice[i].driverdata) release];
-				mice[i].driverdata = NULL;
-				/* send mouse up */
-				SDL_SendMouseButton(i, SDL_RELEASED, SDL_BUTTON_LEFT);
-				/* discontinue search for this touch */
-				found = YES;
-			}
-		}
-		
-		/* grab next touch */
-		touch = (UITouch*)[enumerator nextObject]; 
-	}
-#else
 	if (touch) {
 		/* send mouse up */
 		SDL_SendMouseButton(NULL, SDL_RELEASED, SDL_BUTTON_LEFT);
 	}
+
+#ifdef FIXED_MULTITOUCH
+	while(touch) {
+	  CGPoint locationInView = [touch locationInView: self];
+	  
+
+#ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
+	  SDL_SendFingerDown(touchId,(long)touch,
+			     SDL_FALSE,locationInView.x,locationInView.y,
+			     1);
+#else
+	  int i;
+	  for(i = 0;i < MAX_SIMULTANEOUS_TOUCHES;i++) {
+	    if(finger[i] == touch) {
+	      SDL_SendFingerDown(touchId,i,
+				 SDL_FALSE,locationInView.x,locationInView.y,
+				 1);
+	      break;
+	    }
+	  }
+#endif
+
+	  touch = (UITouch*)[enumerator nextObject]; 
+	}
 #endif
 }
 
@@ -167,31 +174,36 @@
 	NSEnumerator *enumerator = [touches objectEnumerator];
 	UITouch *touch = (UITouch*)[enumerator nextObject];
 	
-#if FIXME_MULTITOUCH
-	while(touch) {
-		/* try to find the mouse associated with this touch */
-		int i, found = NO;
-		for (i=0; i<MAX_SIMULTANEOUS_TOUCHES && !found; i++) {
-			if (mice[i].driverdata == touch) {
-				/* found proper mouse */
-				CGPoint locationInView = [touch locationInView: self];
-				/* send moved event */
-				SDL_SendMouseMotion(i, 0, locationInView.x, locationInView.y, 0);
-				/* discontinue search */
-				found = YES;
-			}
-		}
-		
-		/* grab next touch */
-		touch = (UITouch*)[enumerator nextObject]; 
-	}
-#else
 	if (touch) {
 		CGPoint locationInView = [touch locationInView: self];
 
 		/* send moved event */
 		SDL_SendMouseMotion(NULL, 0, locationInView.x, locationInView.y);
 	}
+
+#ifdef FIXED_MULTITOUCH
+	while(touch) {
+	  CGPoint locationInView = [touch locationInView: self];
+	  
+
+#ifdef IPHONE_TOUCH_EFFICIENT_DANGEROUS
+	  SDL_SendTouchMotion(touchId,(long)touch,
+			      SDL_FALSE,locationInView.x,locationInView.y,
+			      1);
+#else
+	  int i;
+	  for(i = 0;i < MAX_SIMULTANEOUS_TOUCHES;i++) {
+	    if(finger[i] == touch) {
+	      SDL_SendTouchMotion(touchId,i,
+				  SDL_FALSE,locationInView.x,locationInView.y,
+				  1);
+	      break;
+	    }
+	  }
+#endif
+
+	  touch = (UITouch*)[enumerator nextObject]; 
+	}
 #endif
 }
 
--- a/src/video/win32/SDL_win32events.c	Sun Aug 22 11:56:07 2010 -0700
+++ b/src/video/win32/SDL_win32events.c	Sun Aug 22 12:07:55 2010 -0700
@@ -20,9 +20,9 @@
     slouken@libsdl.org
 */
 
-#if (_WIN32_WINNT < 0x0501)
+#if (_WIN32_WINNT < 0x601)
 #undef _WIN32_WINNT
-#define _WIN32_WINNT 0x0501
+#define _WIN32_WINNT 0x601
 #endif
 
 #include "SDL_config.h"
@@ -32,11 +32,14 @@
 #include "SDL_vkeys.h"
 #include "../../events/SDL_events_c.h"
 
-/*#define WMMSG_DEBUG*/
+
+
+#define WMMSG_DEBUG
 #ifdef WMMSG_DEBUG
-#include <stdio.h>
+#include <stdio.h>	
 #include "wmmsg.h"
 #endif
+//#include <stdio.h>
 
 /* Masks for processing the windows KEYDOWN and KEYUP messages */
 #define REPEATED_KEYMASK    (1<<30)
@@ -121,9 +124,10 @@
     if (!data) {
         return CallWindowProc(DefWindowProc, hwnd, msg, wParam, lParam);
     }
+
 #ifdef WMMSG_DEBUG
-    {
-        FILE *log = fopen("wmmsg.txt", "a");
+    {		
+        FILE *log = fopen("wmmsg.txt", "a");		
         fprintf(log, "Received windows message: %p ", hwnd);
         if (msg > MAX_WMMSG) {
             fprintf(log, "%d", msg);
@@ -509,7 +513,39 @@
         }
         returnCode = 0;
         break;
-    }
+	case WM_TOUCH:
+		{
+			//printf("Got Touch Event!\n");
+    
+			FILE *log = fopen("wmmsg.txt", "a");
+			fprintf(log, "Received Touch Message: %p ", hwnd);
+			if (msg > MAX_WMMSG) {
+				fprintf(log, "%d", msg);
+			} else {
+				fprintf(log, "%s", wmtab[msg]);
+			}
+			fprintf(log, "WM_TOUCH = %d -- 0x%X, 0x%X\n",msg, wParam, lParam);
+			fclose(log);
+    
+		}
+		break;
+	case WM_GESTURE:
+		{
+			//printf("Got Touch Event!\n");
+    
+			FILE *log = fopen("wmmsg.txt", "a");
+			fprintf(log, "Received Gesture Message: %p ", hwnd);
+			if (msg > MAX_WMMSG) {
+				fprintf(log, "%d", msg);
+			} else {
+				fprintf(log, "%s", wmtab[msg]);
+			}
+			fprintf(log, "WM_GESTURE = %d -- 0x%X, 0x%X\n",msg, wParam, lParam);
+			fclose(log);
+    
+		}
+		break;		
+	}
 
     /* If there's a window proc, assume it's going to handle messages */
     if (data->wndproc) {
--- a/src/video/win32/SDL_win32video.h	Sun Aug 22 11:56:07 2010 -0700
+++ b/src/video/win32/SDL_win32video.h	Sun Aug 22 12:07:55 2010 -0700
@@ -32,7 +32,14 @@
 #define UNICODE
 #endif
 #undef WINVER
-#define WINVER  0x500           /* Need 0x410 for AlphaBlend() and 0x500 for EnumDisplayDevices() */
+//#define WINVER  0x500           /* Need 0x410 for AlphaBlend() and 0x500 for EnumDisplayDevices() */
+#define WINVER 0x601  /* Need 0x600 (_WIN32_WINNT_WIN7) for WM_Touch */
+#if (_WIN32_WINNT < 0x601)
+#undef _WIN32_WINNT
+#define _WIN32_WINNT 0x601
+#endif
+
+
 #include <windows.h>
 
 #if SDL_VIDEO_RENDER_D3D
--- a/src/video/win32/SDL_win32window.c	Sun Aug 22 11:56:07 2010 -0700
+++ b/src/video/win32/SDL_win32window.c	Sun Aug 22 12:07:55 2010 -0700
@@ -218,6 +218,7 @@
         WIN_SetError("Couldn't create window");
         return -1;
     }
+	//RegisterTouchWindow(hwnd, 0);
 
     WIN_PumpEvents(_this);
 
--- a/src/video/win32/wmmsg.h	Sun Aug 22 11:56:07 2010 -0700
+++ b/src/video/win32/wmmsg.h	Sun Aug 22 12:07:55 2010 -0700
@@ -283,7 +283,7 @@
     "WM_INITMENU",
     "WM_INITMENUPOPUP",
     "UNKNOWN (280)",
-    "UNKNOWN (281)",
+    "WM_GESTURE",
     "UNKNOWN (282)",
     "UNKNOWN (283)",
     "UNKNOWN (284)",
@@ -578,7 +578,7 @@
     "UNKNOWN (573)",
     "UNKNOWN (574)",
     "UNKNOWN (575)",
-    "UNKNOWN (576)",
+    "WM_TOUCH",
     "UNKNOWN (577)",
     "UNKNOWN (578)",
     "UNKNOWN (579)",
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/x11/SDL_eventtouch.c	Sun Aug 22 12:07:55 2010 -0700
@@ -0,0 +1,128 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997-2010 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+#include "SDL_config.h"
+#include "SDL_x11video.h"
+#include "SDL_eventtouch.h"
+#include "../../events/SDL_touch_c.h"
+
+
+#ifdef SDL_INPUT_LINUXEV
+#include <linux/input.h>
+#include <fcntl.h>
+#endif
+
+void
+X11_InitTouch(_THIS)
+{
+#ifdef SDL_INPUT_LINUXEV
+  printf("Initializing touch...\n");
+
+  FILE *fd;
+  fd = fopen("/proc/bus/input/devices","r");
+  
+  char c;
+  int i = 0;
+  char line[256];
+  char tstr[256];
+  int vendor = -1,product = -1,event = -1;
+  while(!feof(fd)) {
+    if(fgets(line,256,fd) <=0) continue;
+    //printf("%s",line);
+    if(line[0] == '\n') {
+      if(vendor == 1386){
+	printf("Wacom... Assuming it is a touch device\n");
+	sprintf(tstr,"/dev/input/event%i",event);
+	printf("At location: %s\n",tstr);
+
+	SDL_Touch touch;
+	touch.pressure_max = 0;
+	touch.pressure_min = 0;
+	touch.id = event; 
+	
+
+	touch.driverdata = SDL_malloc(sizeof(EventTouchData));
+	EventTouchData* data = (EventTouchData*)(touch.driverdata);
+
+	data->x = -1;
+	data->y = -1;
+	data->pressure = -1;
+	data->finger = 0;
+	data->up = SDL_FALSE;
+	
+
+	printf("Opening device...\n");
+	//printf("New Touch - DataPtr: %i\n",data);
+	data->eventStream = open(tstr, 
+				 O_RDONLY | O_NONBLOCK);
+	ioctl (data->eventStream, EVIOCGNAME (sizeof (tstr)), tstr);
+	printf ("Reading From : %s\n", tstr);
+
+
+
+	int abs[5];
+	ioctl(data->eventStream,EVIOCGABS(0),abs);	
+	touch.x_min = abs[1];
+	touch.x_max = abs[2];
+	touch.native_xres = touch.x_max - touch.x_min;
+	ioctl(data->eventStream,EVIOCGABS(ABS_Y),abs);	
+	touch.y_min = abs[1];
+	touch.y_max = abs[2];
+	touch.native_yres = touch.y_max - touch.y_min;
+	ioctl(data->eventStream,EVIOCGABS(ABS_PRESSURE),abs);	
+	touch.pressure_min = abs[1];
+	touch.pressure_max = abs[2];
+	touch.native_pressureres = touch.pressure_max - touch.pressure_min;
+
+	SDL_AddTouch(&touch, tstr);
+      }
+      vendor = -1;
+      product = -1;
+      event = -1;      
+    }
+    else if(line[0] == 'I') {
+      i = 1;
+      while(line[i]) {
+	sscanf(&line[i],"Vendor=%x",&vendor);
+	sscanf(&line[i],"Product=%x",&product);
+	i++;
+      }
+    }
+    else if(line[0] == 'H') {
+      i = 1;
+      while(line[i]) {
+	sscanf(&line[i],"event%d",&event);
+	i++;
+      }
+    }
+  }
+  
+  close(fd);
+#endif
+}
+
+void
+X11_QuitTouch(_THIS)
+{
+    SDL_TouchQuit();
+}
+
+/* vi: set ts=4 sw=4 expandtab: */
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/x11/SDL_eventtouch.h	Sun Aug 22 12:07:55 2010 -0700
@@ -0,0 +1,43 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997-2010 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Lesser General Public
+    License as published by the Free Software Foundation; either
+    version 2.1 of the License, or (at your option) any later version.
+
+    This library is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+    Lesser General Public License for more details.
+
+    You should have received a copy of the GNU Lesser General Public
+    License along with this library; if not, write to the Free Software
+    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+#include "SDL_config.h"
+
+#ifndef _SDL_eventtouch_h
+#define _SDL_eventtouch_h
+
+
+//What should this be?
+#if SDL_VIDEO_DRIVER_X11_XINPUT
+typedef struct EventTouchData
+{
+    int x,y,pressure,finger; //Temporary Variables until sync
+    int eventStream;
+    SDL_bool up;
+} EventTouchData;
+#endif
+
+extern void X11_InitTouch(_THIS);
+extern void X11_QuitTouch(_THIS);
+
+#endif /* _SDL_eventtouch_h */
+
+/* vi: set ts=4 sw=4 expandtab: */
--- a/src/video/x11/SDL_x11events.c	Sun Aug 22 11:56:07 2010 -0700
+++ b/src/video/x11/SDL_x11events.c	Sun Aug 22 12:07:55 2010 -0700
@@ -30,10 +30,18 @@
 #include "SDL_x11video.h"
 #include "../../events/SDL_events_c.h"
 #include "../../events/SDL_mouse_c.h"
+#include "../../events/SDL_touch_c.h"
 
 #include "SDL_timer.h"
 #include "SDL_syswm.h"
 
+#include <stdio.h>
+
+#ifdef SDL_INPUT_LINUXEV
+//Touch Input/event* includes
+#include <linux/input.h>
+#include <fcntl.h>
+#endif
 /*#define DEBUG_XEVENTS*/
 
 /* Check to see if this is a repeated key.
@@ -121,7 +129,6 @@
             SDL_SetMouseFocus(data->window);
         }
         break;
-
         /* Losing mouse coverage? */
     case LeaveNotify:{
 #ifdef DEBUG_XEVENTS
@@ -495,6 +502,79 @@
     while (X11_Pending(data->display)) {
         X11_DispatchEvent(_this);
     }
+
+#ifdef SDL_INPUT_LINUXEV
+    /* Process Touch events - TODO When X gets touch support, use that instead*/
+    int i = 0,rd;
+    char name[256];
+    struct input_event ev[64];
+    int size = sizeof (struct input_event);
+
+    for(i = 0;i < SDL_GetNumTouch();++i) {
+	SDL_Touch* touch = SDL_GetTouchIndex(i);
+	if(!touch) printf("Touch %i/%i DNE\n",i,SDL_GetNumTouch());
+	EventTouchData* data;
+	data = (EventTouchData*)(touch->driverdata);
+	if(data == NULL) {
+	  printf("No driver data\n");
+	  continue;
+	}
+	if(data->eventStream <= 0) 
+	    printf("Error: Couldn't open stream\n");
+	rd = read(data->eventStream, ev, size * 64);
+	//printf("Got %i/%i bytes\n",rd,size);
+	if(rd >= size) {
+	    for (i = 0; i < rd / sizeof(struct input_event); i++) {
+		switch (ev[i].type) {
+		case EV_ABS:
+		    //printf("Got position x: %i!\n",data->x);
+		    switch (ev[i].code) {
+			case ABS_X:
+			    data->x = ev[i].value;
+			    break;
+			case ABS_Y:
+			    data->y = ev[i].value;
+			    break;
+			case ABS_PRESSURE:
+			    data->pressure = ev[i].value;
+			    if(data->pressure < 0) data->pressure = 0;
+			    break;
+			case ABS_MISC:
+			    if(ev[i].value == 0)
+			        data->up = SDL_TRUE;			    
+			    break;
+			}
+		    break;
+		case EV_MSC:
+		    if(ev[i].code == MSC_SERIAL)
+			data->finger = ev[i].value;
+		    break;
+		case EV_SYN:
+		  //printf("Id: %i\n",touch->id); 
+		  if(data->up) {
+		      SDL_SendFingerDown(touch->id,data->finger,
+			  	       SDL_FALSE,data->x,data->y,
+				       data->pressure);		    
+		  }
+		  else if(data->x >= 0 || data->y >= 0)
+		    SDL_SendTouchMotion(touch->id,data->finger, 
+					SDL_FALSE,data->x,data->y,
+					data->pressure);
+		  
+		    //printf("Synched: %i tx: %i, ty: %i\n",
+		    //	   data->finger,data->x,data->y);
+		  data->x = -1;
+		  data->y = -1;
+		  data->pressure = -1;
+		  data->finger = 0;
+		  data->up = SDL_FALSE;
+		    
+		  break;		
+		}
+	    }
+	}
+    }
+#endif
 }
 
 /* This is so wrong it hurts */
--- a/src/video/x11/SDL_x11video.c	Sun Aug 22 11:56:07 2010 -0700
+++ b/src/video/x11/SDL_x11video.c	Sun Aug 22 12:07:55 2010 -0700
@@ -25,6 +25,7 @@
 
 #include "SDL_video.h"
 #include "SDL_mouse.h"
+#include "SDL_eventtouch.h" 
 #include "../SDL_sysvideo.h"
 #include "../SDL_pixels_c.h"
 
@@ -354,6 +355,7 @@
     }
     X11_InitMouse(_this);
 
+    X11_InitTouch(_this);
     return 0;
 }
 
@@ -374,6 +376,7 @@
     X11_QuitModes(_this);
     X11_QuitKeyboard(_this);
     X11_QuitMouse(_this);
+    X11_QuitTouch(_this);
 }
 
 SDL_bool
--- a/src/video/x11/SDL_x11video.h	Sun Aug 22 11:56:07 2010 -0700
+++ b/src/video/x11/SDL_x11video.h	Sun Aug 22 12:07:55 2010 -0700
@@ -62,6 +62,7 @@
 #include "SDL_x11keyboard.h"
 #include "SDL_x11modes.h"
 #include "SDL_x11mouse.h"
+#include "SDL_eventtouch.h"
 #include "SDL_x11opengl.h"
 #include "SDL_x11window.h"
 
--- a/test/Makefile.in	Sun Aug 22 11:56:07 2010 -0700
+++ b/test/Makefile.in	Sun Aug 22 12:07:55 2010 -0700
@@ -7,7 +7,7 @@
 CFLAGS  = @CFLAGS@
 LIBS	= @LIBS@
 
-TARGETS = checkkeys$(EXE) graywin$(EXE) loopwave$(EXE) testalpha$(EXE) testatomic$(EXE) testaudioinfo$(EXE) testbitmap$(EXE) testblitspeed$(EXE) testcursor$(EXE) testdraw2$(EXE) testdyngles$(EXE) testdyngl$(EXE) testerror$(EXE) testfile$(EXE) testfill$(EXE) testgamma$(EXE) testgl2$(EXE) testgles$(EXE) testgl$(EXE) testhaptic$(EXE) testhread$(EXE) testiconv$(EXE) testime$(EXE) testintersections$(EXE) testjoystick$(EXE) testkeys$(EXE) testloadso$(EXE) testlock$(EXE) testmultiaudio$(EXE) testoverlay2$(EXE) testoverlay$(EXE) testpalette$(EXE) testplatform$(EXE) testpower$(EXE) testresample$(EXE) testsem$(EXE) testsprite2$(EXE) testsprite$(EXE) testspriteminimal$(EXE) testtimer$(EXE) testver$(EXE) testvidinfo$(EXE) testwin$(EXE) testwm2$(EXE) testwm$(EXE) threadwin$(EXE) torturethread$(EXE)
+TARGETS = checkkeys$(EXE) graywin$(EXE) loopwave$(EXE) testalpha$(EXE) testatomic$(EXE) testaudioinfo$(EXE) testbitmap$(EXE) testblitspeed$(EXE) testcursor$(EXE) testdraw2$(EXE) testdyngles$(EXE) testdyngl$(EXE) testerror$(EXE) testfile$(EXE) testfill$(EXE) testgamma$(EXE) testgl2$(EXE) testgles$(EXE) testgl$(EXE) testhaptic$(EXE) testhread$(EXE) testiconv$(EXE) testime$(EXE) testintersections$(EXE) testjoystick$(EXE) testkeys$(EXE) testloadso$(EXE) testlock$(EXE) testmultiaudio$(EXE) testoverlay2$(EXE) testoverlay$(EXE) testpalette$(EXE) testplatform$(EXE) testpower$(EXE) testresample$(EXE) testsem$(EXE) testsprite2$(EXE) testsprite$(EXE) testspriteminimal$(EXE) testtimer$(EXE) testver$(EXE) testvidinfo$(EXE) testwin$(EXE) testwm2$(EXE) testwm$(EXE) threadwin$(EXE) torturethread$(EXE) testgesture$(EXE)
 
 all: Makefile $(TARGETS)
 
@@ -151,6 +151,9 @@
 
 testatomic$(EXE): $(srcdir)/testatomic.c
 	$(CC) -o $@ $? $(CFLAGS) $(LIBS)
+
+testgesture$(EXE): $(srcdir)/testgesture.c
+	$(CC) -o $@ $? $(CFLAGS) $(LIBS)
  
 testime$(EXE): $(srcdir)/testime.c
 	$(CC) -o $@ $? $(CFLAGS) $(LIBS) @SDL_TTF_LIB@
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/test/testgesture.c	Sun Aug 22 12:07:55 2010 -0700
@@ -0,0 +1,297 @@
+/*  Usage:
+ *  Spacebar to begin recording a gesture on all touches.
+ *  s to save all touches into "./gestureSave"
+ *  l to load all touches from "./gestureSave"
+ */
+
+#include <stdio.h>
+#include <SDL.h>
+#include <math.h>
+#include <SDL_touch.h>
+#include <SDL_gesture.h>
+
+
+/* Make sure we have good macros for printing 32 and 64 bit values */
+#ifndef PRIs32
+#define PRIs32 "d"
+#endif
+#ifndef PRIu32
+#define PRIu32 "u"
+#endif
+#ifndef PRIs64
+#ifdef __WIN32__
+#define PRIs64 "I64"
+#else
+#define PRIs64 "lld"
+#endif
+#endif
+#ifndef PRIu64
+#ifdef __WIN32__
+#define PRIu64 "I64u"
+#else
+#define PRIu64 "llu"
+#endif
+#endif
+
+#define WIDTH 640
+#define HEIGHT 480
+#define BPP 4
+#define DEPTH 32
+
+//MUST BE A POWER OF 2!
+#define EVENT_BUF_SIZE 256
+
+
+#define VERBOSE SDL_FALSE
+
+SDL_Event events[EVENT_BUF_SIZE];
+int eventWrite;
+
+int colors[7] = {0xFF,0xFF00,0xFF0000,0xFFFF00,0x00FFFF,0xFF00FF,0xFFFFFF};
+
+typedef struct {
+  float x,y;
+} Point;
+
+typedef struct {
+  float ang,r;
+  Point p;
+} Knob;
+
+Knob knob;
+
+void handler (int sig)
+{
+  printf ("\exiting...(%d)\n", sig);
+  exit (0);
+}
+
+void perror_exit (char *error)
+{
+  perror (error);
+  handler (9);
+}
+
+void setpix(SDL_Surface *screen, int x, int y, unsigned int col)
+{
+  Uint32 *pixmem32;
+  Uint32 colour;
+  
+  if((unsigned)x > screen->w) return;
+  if((unsigned)y > screen->h) return;
+
+  pixmem32 = (Uint32*) screen->pixels  + y*screen->pitch/BPP + x;
+  
+  Uint8 r,g,b;
+  float a;
+  
+  memcpy(&colour,pixmem32,screen->format->BytesPerPixel);
+
+  SDL_GetRGB(colour,screen->format,&r,&g,&b);
+  //r = 0;g = 0; b = 0;
+  a = (col>>24)&0xFF;
+  if(a == 0) a = 0xFF; //Hack, to make things easier.
+  a /= 0xFF;
+  r = r*(1-a) + ((col>>16)&0xFF)*(a);
+  g = g*(1-a) + ((col>> 8)&0xFF)*(a);
+  b = b*(1-a) + ((col>> 0)&0xFF)*(a);
+  colour = SDL_MapRGB( screen->format,r, g, b);
+  
+
+  *pixmem32 = colour;
+}
+
+void drawLine(SDL_Surface *screen,int x0,int y0,int x1,int y1,unsigned int col) {
+  float t;
+  for(t=0;t<1;t+=1.f/SDL_max(abs(x0-x1),abs(y0-y1)))
+    setpix(screen,x1+t*(x0-x1),y1+t*(y0-y1),col);
+}
+
+void drawCircle(SDL_Surface* screen,int x,int y,int r,unsigned int c)
+{
+  int tx,ty;
+  float xr;
+  for(ty = -abs(r);ty <= abs(r);ty++) {
+    xr = sqrt(r*r - ty*ty);
+    if(r > 0) { //r > 0 ==> filled circle
+      for(tx=-xr+.5;tx<=xr-.5;tx++) {
+	setpix(screen,x+tx,y+ty,c);
+      }
+    }
+    else {
+      setpix(screen,x-xr+.5,y+ty,c);
+      setpix(screen,x+xr-.5,y+ty,c);
+    }
+  }
+}
+
+void drawKnob(SDL_Surface* screen,Knob k) {
+  drawCircle(screen,k.p.x*screen->w,k.p.y*screen->h,k.r*screen->w,0xFFFFFF);  
+  drawCircle(screen,(k.p.x+k.r/2*cos(k.ang))*screen->w,
+  	            (k.p.y+k.r/2*sin(k.ang))*screen->h,k.r/4*screen->w,0);
+}
+
+void DrawScreen(SDL_Surface* screen)
+{
+  int x, y;
+  if(SDL_MUSTLOCK(screen))
+    {                                              
+      if(SDL_LockSurface(screen) < 0) return;
+    }
+  for(y = 0;y < screen->h;y++)
+    for(x = 0;x < screen->w;x++)
+	setpix(screen,x,y,((x%255)<<16) + ((y%255)<<8) + (x+y)%255);
+
+  int i;
+  //draw Touch History
+  for(i = SDL_max(0,eventWrite - EVENT_BUF_SIZE);i < eventWrite;i++) {
+    SDL_Event event = events[i&(EVENT_BUF_SIZE-1)];
+    int age = eventWrite - i - 1;
+    if(event.type == SDL_FINGERMOTION || 
+       event.type == SDL_FINGERDOWN ||
+       event.type == SDL_FINGERUP) {
+      SDL_Touch* inTouch = SDL_GetTouch(event.tfinger.touchId);
+      if(inTouch == NULL) continue;
+
+      float x = ((float)event.tfinger.x)/inTouch->xres;
+      float y = ((float)event.tfinger.y)/inTouch->yres;      
+      
+      //draw the touch:      
+      unsigned int c = colors[event.tfinger.touchId%7]; 
+      unsigned int col = 
+	((unsigned int)(c*(.1+.85))) |
+	((unsigned int)((0xFF*(1-((float)age)/EVENT_BUF_SIZE))) & 0xFF)<<24;
+
+      if(event.type == SDL_FINGERMOTION)
+	drawCircle(screen,x*screen->w,y*screen->h,5,col);
+      else if(event.type == SDL_FINGERDOWN)
+	drawCircle(screen,x*screen->w,y*screen->h,-10,col);     
+    }
+  }
+  
+  if(knob.p.x > 0)
+    drawKnob(screen,knob);
+  
+  if(SDL_MUSTLOCK(screen)) SDL_UnlockSurface(screen);
+  SDL_Flip(screen);
+}
+
+SDL_Surface* initScreen(int width,int height)
+{
+  return SDL_SetVideoMode(width, height, DEPTH,
+			  SDL_HWSURFACE | SDL_RESIZABLE);
+}
+
+int main(int argc, char* argv[])
+{  
+  SDL_Surface *screen;
+  SDL_Event event;
+
+  //gesture variables
+  knob.r = .1;
+  knob.ang = 0;
+
+  
+  SDL_bool quitting = SDL_FALSE;
+  SDL_RWops *src;
+
+  if (SDL_Init(SDL_INIT_VIDEO) < 0 ) return 1;
+  
+  if (!(screen = initScreen(WIDTH,HEIGHT)))
+    {
+      SDL_Quit();
+      return 1;
+    }
+
+  while(!quitting) {
+    while(SDL_PollEvent(&event)) 
+      {
+	//Record _all_ events
+	events[eventWrite & (EVENT_BUF_SIZE-1)] = event;
+	eventWrite++;
+	
+	switch (event.type) 
+	  {
+	  case SDL_QUIT:
+	    quitting = SDL_TRUE;
+	    break;
+	  case SDL_KEYDOWN:
+	    switch (event.key.keysym.sym)
+	      {
+	      case SDLK_SPACE:
+		SDL_RecordGesture(-1);
+		break;
+	      case SDLK_s:
+		src = SDL_RWFromFile("gestureSave","w");
+		printf("Wrote %i templates\n",SDL_SaveAllDollarTemplates(src));
+		SDL_RWclose(src);
+		break;
+	      case SDLK_l:
+		src = SDL_RWFromFile("gestureSave","r");
+		printf("Loaded: %i\n",SDL_LoadDollarTemplates(-1,src));
+		SDL_RWclose(src);
+		break;
+	      case SDLK_ESCAPE:
+		quitting = SDL_TRUE;
+		break;
+	    }
+	    break;
+	  case SDL_VIDEORESIZE:
+	    if (!(screen = initScreen(event.resize.w,
+				      event.resize.h)))
+	      {
+		SDL_Quit();
+		return 1;
+	      }
+	    break;
+	  case SDL_FINGERMOTION:    
+	    ;
+#if VERBOSE
+	    printf("Finger: %i,x: %i, y: %i\n",event.tfinger.fingerId,
+	    	   event.tfinger.x,event.tfinger.y);
+#endif
+	    SDL_Touch* inTouch = SDL_GetTouch(event.tfinger.touchId);
+	    SDL_Finger* inFinger = SDL_GetFinger(inTouch,event.tfinger.fingerId);
+	    break;	    
+	  case SDL_FINGERDOWN:
+#if VERBOSE
+	    printf("Finger: %"PRIs64" down - x: %i, y: %i\n",
+		   event.tfinger.fingerId,event.tfinger.x,event.tfinger.y);
+#endif
+	    break;
+	  case SDL_FINGERUP:
+#if VERBOSE
+	    printf("Finger: %"PRIs64" up - x: %i, y: %i\n",
+	    	   event.tfinger.fingerId,event.tfinger.x,event.tfinger.y);
+#endif
+	    break;
+	  case SDL_MULTIGESTURE:
+#if VERBOSE	    
+	    printf("Multi Gesture: x = %f, y = %f, dAng = %f, dR = %f\n",
+		   event.mgesture.x,
+		   event.mgesture.y,
+		   event.mgesture.dTheta,
+		   event.mgesture.dDist);
+	    printf("MG: numDownTouch = %i\n",event.mgesture.numFingers);
+#endif
+	    knob.p.x = event.mgesture.x;
+	    knob.p.y = event.mgesture.y;
+	    knob.ang += event.mgesture.dTheta;
+	    knob.r += event.mgesture.dDist;
+	    break;
+	  case SDL_DOLLARGESTURE:
+	    printf("Gesture %"PRIs64" performed, error: %f\n",
+		   event.dgesture.gestureId,
+		   event.dgesture.error);
+	    break;
+	  case SDL_DOLLARRECORD:
+	    printf("Recorded gesture: %"PRIs64"\n",event.dgesture.gestureId);
+	    break;
+	  }
+      }
+    DrawScreen(screen);
+  }  
+  SDL_Quit();  
+  return 0;
+}
+