Updated Windows CE/PocketPC support...adds GAPI driver, landscape mode,
authorRyan C. Gordon <icculus@icculus.org>
Thu, 19 Jan 2006 08:43:00 +0000
changeset 1251 86d0d01290ea
parent 1250 a4d515d0fc3a
child 1252 57be1c741b8b
Updated Windows CE/PocketPC support...adds GAPI driver, landscape mode, updated project files, VS2005 support, VGA mode, more device support, etc, etc, etc. Fixes Bugzilla #47 and #28. --ryan.
README.WinCE
VisualCE.zip
configure.in
src/thread/win32/SDL_systhread.c
src/thread/win32/win_ce_semaphore.c
src/video/Makefile.am
src/video/SDL_surface.c
src/video/SDL_sysvideo.h
src/video/SDL_video.c
src/video/gapi/.cvsignore
src/video/gapi/Makefile.am
src/video/gapi/SDL_gapivideo.c
src/video/gapi/SDL_gapivideo.h
src/video/wincommon/SDL_lowvideo.h
src/video/wincommon/SDL_sysevents.c
src/video/wincommon/SDL_sysmouse.c
src/video/windib/SDL_dibevents.c
src/video/windib/SDL_dibvideo.c
src/video/windib/SDL_dibvideo.h
--- a/README.WinCE	Thu Jan 19 08:36:41 2006 +0000
+++ b/README.WinCE	Thu Jan 19 08:43:00 2006 +0000
@@ -1,5 +1,24 @@
 
-Project files for embedded Visual C++ 4.0 can be found in VisualCE.zip
+Project files for embedded Visual C++ 3.0, 4.0 and 
+Visual Studio 2005 can be found in VisualCE.zip
+
+SDL supports GAPI and WinDib output for Windows CE.
+
+GAPI driver supports:
+
+- all possible WinCE devices (Pocket PC, Smartphones, HPC)
+  with different orientations of video memory and resolutions.
+- 4, 8 and 16 bpp devices
+- special handling of 8bpp on 8bpp devices
+- VGA mode, you can even switch between VGA and GAPI in runtime
+  (between 240x320 and 480x640 for example). On VGA devices you can
+  use either GAPI or VGA.
+- Landscape mode and automatic rotation of buttons and stylus coordinates.
+  To enable landscape mode make width of video screen bigger than height.
+  For example: 
+    SDL_SetVideoMode(320,240,16,SDL_FULLSCREEN)
+- WM2005
+- SDL_ListModes
 
 NOTE:
 There are several SDL features not available in the WinCE port of SDL.
Binary file VisualCE.zip has changed
--- a/configure.in	Thu Jan 19 08:36:41 2006 +0000
+++ b/configure.in	Thu Jan 19 08:43:00 2006 +0000
@@ -3140,6 +3140,7 @@
 src/video/wincommon/Makefile
 src/video/windib/Makefile
 src/video/windx5/Makefile
+src/video/gapi/Makefile
 src/video/x11/Makefile
 src/video/xbios/Makefile
 src/video/XFree86/Makefile
--- a/src/thread/win32/SDL_systhread.c	Thu Jan 19 08:36:41 2006 +0000
+++ b/src/thread/win32/SDL_systhread.c	Thu Jan 19 08:43:00 2006 +0000
@@ -30,7 +30,10 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <windows.h>
+
+#ifndef _WIN32_WCE
 #include <process.h>
+#endif
 
 #include "SDL_error.h"
 #include "SDL_thread.h"
@@ -53,9 +56,14 @@
 	 * have to use _beginthreadex if we want the returned handle
 	 * to be accessible after the thread exits
 	 * threads created with _beginthread auto-close the handle
+	 * Windows CE still use CreateThread.
 	 */
+#ifdef _WIN32_WCE
+	thread->handle = CreateThread(NULL, 0, RunThread, args, 0, &threadid);
+#else
 	thread->handle = (SYS_ThreadHandle) _beginthreadex(NULL, 0, RunThread,
 			args, 0, &threadid);
+#endif
 	if (thread->handle == NULL) {
 		SDL_SetError("Not enough resources to create thread");
 		return(-1);
--- a/src/thread/win32/win_ce_semaphore.c	Thu Jan 19 08:36:41 2006 +0000
+++ b/src/thread/win32/win_ce_semaphore.c	Thu Jan 19 08:43:00 2006 +0000
@@ -201,9 +201,9 @@
    BOOL ok = TRUE;
 
    if (hSynch == NULL) return NULL;
-   if (Flags & 4 == 1 && hSynch->hEvent == NULL) ok = FALSE;
-   if (Flags & 2 == 1 && hSynch->hMutex == NULL) ok = FALSE;
-   if (Flags & 1 == 1 && hSynch->hEvent == NULL) ok = FALSE;
+   if ((Flags & 4) == 1 && (hSynch->hEvent == NULL)) ok = FALSE;
+   if ((Flags & 2) == 1 && (hSynch->hMutex == NULL)) ok = FALSE;
+   if ((Flags & 1) == 1 && (hSynch->hEvent == NULL)) ok = FALSE;
    if (!ok) 
    {
       CloseSynchHandle (hSynch);
--- a/src/video/Makefile.am	Thu Jan 19 08:36:41 2006 +0000
+++ b/src/video/Makefile.am	Thu Jan 19 08:43:00 2006 +0000
@@ -9,7 +9,7 @@
                wincommon windib windx5 \
                maccommon macdsp macrom riscos quartz \
                bwindow ps2gs photon cybergfx epoc picogui \
-               ataricommon xbios gem dc qtopia XFree86 wscons \
+               ataricommon xbios gem dc qtopia XFree86 wscons gapi \
                ipod os2fslib
 
 DRIVERS = @VIDEO_DRIVERS@
--- a/src/video/SDL_surface.c	Thu Jan 19 08:36:41 2006 +0000
+++ b/src/video/SDL_surface.c	Thu Jan 19 08:43:00 2006 +0000
@@ -39,6 +39,7 @@
 #include "SDL_memops.h"
 #include "SDL_leaks.h"
 
+
 /* Public routines */
 /*
  * Create an empty RGB surface of the appropriate depth
--- a/src/video/SDL_sysvideo.h	Thu Jan 19 08:36:41 2006 +0000
+++ b/src/video/SDL_sysvideo.h	Thu Jan 19 08:43:00 2006 +0000
@@ -365,6 +365,9 @@
 #ifdef ENABLE_AALIB
 extern VideoBootStrap AALIB_bootstrap;
 #endif
+#ifdef ENABLE_GAPI
+extern VideoBootStrap GAPI_bootstrap;
+#endif
 #ifdef ENABLE_WINDIB
 extern VideoBootStrap WINDIB_bootstrap;
 #endif
--- a/src/video/SDL_video.c	Thu Jan 19 08:36:41 2006 +0000
+++ b/src/video/SDL_video.c	Thu Jan 19 08:43:00 2006 +0000
@@ -87,6 +87,9 @@
 #ifdef ENABLE_AALIB
 	&AALIB_bootstrap,
 #endif
+#ifdef ENABLE_GAPI
+	&GAPI_bootstrap,
+#endif
 #ifdef ENABLE_WINDIB
 	&WINDIB_bootstrap,
 #endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/gapi/.cvsignore	Thu Jan 19 08:43:00 2006 +0000
@@ -0,0 +1,6 @@
+Makefile.in
+Makefile
+.libs
+*.o
+*.lo
+*.la
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/gapi/Makefile.am	Thu Jan 19 08:43:00 2006 +0000
@@ -0,0 +1,10 @@
+
+## Makefile.am for SDL using the PocketPC GAPI video driver
+
+noinst_LTLIBRARIES = libvideo_gapi.la
+libvideo_gapi_la_SOURCES = $(GAPI_SRCS)
+
+# The SDL GAPI driver sources
+GAPI_SRCS = 			\
+	SDL_gapivideo.c		\
+	SDL_gapivideo.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/gapi/SDL_gapivideo.c	Thu Jan 19 08:43:00 2006 +0000
@@ -0,0 +1,1127 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997-2004 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+
+#ifdef SAVE_RCSID
+static char rcsid =
+ "@(#) $Id$";
+#endif
+
+/* Pocket PC GAPI SDL video driver implementation;
+Implemented by Dmitry Yakimov - support@activekitten.com
+Inspired by http://arisme.free.fr/ports/SDL.php
+*/
+
+// TODO: copy surface on window when lost focus
+// TODO: test buttons rotation
+// TODO: test on be300 and HPC ( check WinDib fullscreen keys catching )
+// TODO: test on smartphones
+// TODO: windib on SH3 PPC2000 landscape test
+// TODO: optimize 8bpp landscape mode
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "SDL.h"
+#include "SDL_error.h"
+#include "SDL_video.h"
+#include "SDL_mouse.h"
+#include "SDL_sysvideo.h"
+#include "SDL_pixels_c.h"
+#include "SDL_events_c.h"
+
+#include "SDL_syswm_c.h"
+#include "SDL_sysmouse_c.h"
+#include "SDL_dibevents_c.h" 
+
+#include "SDL_gapivideo.h"
+
+#define GAPIVID_DRIVER_NAME "gapi"
+
+#if defined(DEBUG) || defined (_DEBUG) || defined(NDEBUG)
+#define REPORT_VIDEO_INFO 1
+#else
+#define REPORT_VIDEO_INFO 0
+#endif
+
+// for testing with GapiEmu
+#define USE_GAPI_EMU 0
+
+#if USE_GAPI_EMU && !REPORT_VIDEO_INFO
+#pragma message("Warning: Using GapiEmu in release build. I assume you'd like to set USE_GAPI_EMU to zero.")
+#endif
+
+// defined and used in SDL_sysevents.c
+extern HINSTANCE aygshell;
+extern void SDL_UnregisterApp();
+extern int DIB_AddMode(_THIS, int bpp, int w, int h);
+
+/* Initialization/Query functions */
+static int GAPI_VideoInit(_THIS, SDL_PixelFormat *vformat);
+static SDL_Rect **GAPI_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags);
+static SDL_Surface *GAPI_SetVideoMode(_THIS, SDL_Surface *current, int width, int height, int bpp, Uint32 flags);
+static int GAPI_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors);
+static void GAPI_VideoQuit(_THIS);
+
+/* Hardware surface functions */
+static int GAPI_AllocHWSurface(_THIS, SDL_Surface *surface);
+static int GAPI_LockHWSurface(_THIS, SDL_Surface *surface);
+static void GAPI_UnlockHWSurface(_THIS, SDL_Surface *surface);
+static void GAPI_FreeHWSurface(_THIS, SDL_Surface *surface);
+
+/* Windows message handling functions, will not be processed */
+static void GAPI_RealizePalette(_THIS);
+static void GAPI_PaletteChanged(_THIS, HWND window);
+static void GAPI_WinPAINT(_THIS, HDC hdc); 
+
+/* etc. */
+static void GAPI_UpdateRects(_THIS, int numrects, SDL_Rect *rects);
+
+static HMODULE g_hGapiLib = 0;
+#define LINK(type,name,import) \
+	if( g_hGapiLib ) \
+		name = (PFN##type)GetProcAddress( g_hGapiLib, _T(import) ); 
+
+static char g_bRawBufferAvailable = 0;
+
+/* GAPI driver bootstrap functions */
+
+/* hi res definitions */
+typedef struct _RawFrameBufferInfo
+{
+   WORD wFormat;
+   WORD wBPP;
+   VOID *pFramePointer;
+   int  cxStride;
+   int  cyStride;
+   int  cxPixels;
+   int  cyPixels;
+} RawFrameBufferInfo; 
+
+static struct _RawFrameBufferInfo g_RawFrameBufferInfo = {0};
+
+#define GETRAWFRAMEBUFFER   0x00020001
+
+#define FORMAT_565 1
+#define FORMAT_555 2
+#define FORMAT_OTHER 3 
+
+static int GAPI_Available(void)
+{
+	// try to use VGA display, even on emulator
+	HDC hdc = GetDC(NULL); 
+	int result = ExtEscape(hdc, GETRAWFRAMEBUFFER, 0, NULL, sizeof(RawFrameBufferInfo), (char *)&g_RawFrameBufferInfo);
+	ReleaseDC(NULL, hdc);
+	g_bRawBufferAvailable = result > 0;
+
+#if USE_GAPI_EMU
+	g_hGapiLib = LoadLibrary(_T("GAPI_Emu.dll"));
+	if( !g_hGapiLib )
+	{
+		SDL_SetError("Gapi Emu not found!");
+	}
+	return g_hGapiLib != 0;
+#endif
+
+	// try to find gx.dll
+	g_hGapiLib = LoadLibrary(_T("\\Windows\\gx.dll"));
+	if( !g_hGapiLib )
+	{
+		g_hGapiLib = LoadLibrary(_T("gx.dll"));
+		if( !g_hGapiLib ) return g_bRawBufferAvailable;
+	}
+
+	return(1);
+}
+
+static int cmpmodes(const void *va, const void *vb)
+{
+    SDL_Rect *a = *(SDL_Rect **)va;
+    SDL_Rect *b = *(SDL_Rect **)vb;
+    if ( a->w == b->w )
+        return b->h - a->h;
+    else
+        return b->w - a->w;
+}
+
+static int GAPI_AddMode(_THIS, int bpp, int w, int h)
+{
+	SDL_Rect *mode;
+	int i, index;
+	int next_mode;
+
+	/* Check to see if we already have this mode */
+	if ( bpp < 8 ) {  /* Not supported */
+		return(0);
+	}
+	index = ((bpp+7)/8)-1;
+	for ( i=0; i<gapi->SDL_nummodes[index]; ++i ) {
+		mode = gapi->SDL_modelist[index][i];
+		if ( (mode->w == w) && (mode->h == h) ) {
+			return(0);
+		}
+	}
+
+	/* Set up the new video mode rectangle */
+	mode = (SDL_Rect *)malloc(sizeof *mode);
+	if ( mode == NULL ) {
+		SDL_OutOfMemory();
+		return(-1);
+	}
+	mode->x = 0;
+	mode->y = 0;
+	mode->w = w;
+	mode->h = h;
+
+	/* Allocate the new list of modes, and fill in the new mode */
+	next_mode = gapi->SDL_nummodes[index];
+	gapi->SDL_modelist[index] = (SDL_Rect **)
+	       realloc(gapi->SDL_modelist[index], (1+next_mode+1)*sizeof(SDL_Rect *));
+	if ( gapi->SDL_modelist[index] == NULL ) {
+		SDL_OutOfMemory();
+		gapi->SDL_nummodes[index] = 0;
+		free(mode);
+		return(-1);
+	}
+	gapi->SDL_modelist[index][next_mode] = mode;
+	gapi->SDL_modelist[index][next_mode+1] = NULL;
+	gapi->SDL_nummodes[index]++;
+
+	return(0);
+}
+
+static void GAPI_DeleteDevice(SDL_VideoDevice *device)
+{
+	if( g_hGapiLib )
+	{
+		FreeLibrary(g_hGapiLib);
+		g_hGapiLib = 0;
+	}
+	free(device->hidden);
+	free(device);
+}
+
+static SDL_VideoDevice *GAPI_CreateDevice(int devindex)
+{
+	SDL_VideoDevice *device;
+
+	if( !g_hGapiLib && !g_bRawBufferAvailable)
+	{
+		if( !GAPI_Available() )
+		{
+			SDL_SetError("GAPI dll is not found and VGA mode is not available!");
+			return 0;
+		}
+	}
+
+	/* Initialize all variables that we clean on shutdown */
+	device = (SDL_VideoDevice *)malloc(sizeof(SDL_VideoDevice));
+	if ( device ) {
+		memset(device, 0, (sizeof *device));
+		device->hidden = (struct SDL_PrivateVideoData *)
+				malloc((sizeof *device->hidden));
+	}
+	if ( (device == NULL) || (device->hidden == NULL) ) {
+		SDL_OutOfMemory();
+		if ( device ) {
+			free(device);
+		}
+		return(0);
+	}
+	memset(device->hidden, 0, (sizeof *device->hidden));
+
+	/* Set the function pointers */
+	device->VideoInit = GAPI_VideoInit;
+	device->ListModes = GAPI_ListModes;
+	device->SetVideoMode = GAPI_SetVideoMode;
+	device->UpdateMouse = WIN_UpdateMouse; 
+	device->CreateYUVOverlay = NULL;
+	device->SetColors = GAPI_SetColors;
+	device->UpdateRects = GAPI_UpdateRects;
+	device->VideoQuit = GAPI_VideoQuit;
+	device->AllocHWSurface = GAPI_AllocHWSurface;
+	device->CheckHWBlit = NULL;
+	device->FillHWRect = NULL;
+	device->SetHWColorKey = NULL;
+	device->SetHWAlpha = NULL;
+	device->LockHWSurface = GAPI_LockHWSurface;
+	device->UnlockHWSurface = GAPI_UnlockHWSurface;
+	device->FlipHWSurface = NULL;
+	device->FreeHWSurface = GAPI_FreeHWSurface;
+	device->SetCaption = WIN_SetWMCaption;
+	device->SetIcon = WIN_SetWMIcon;
+	device->IconifyWindow = WIN_IconifyWindow;
+	device->GrabInput = WIN_GrabInput;
+	device->GetWMInfo = WIN_GetWMInfo;
+	device->FreeWMCursor = WIN_FreeWMCursor;
+	device->CreateWMCursor = WIN_CreateWMCursor; 
+	device->ShowWMCursor = WIN_ShowWMCursor;	
+	device->WarpWMCursor = WIN_WarpWMCursor; 
+    device->CheckMouseMode = WIN_CheckMouseMode;
+	device->InitOSKeymap = DIB_InitOSKeymap;
+	device->PumpEvents = DIB_PumpEvents;
+
+	/* Set up the windows message handling functions */
+	WIN_RealizePalette = GAPI_RealizePalette;
+	WIN_PaletteChanged = GAPI_PaletteChanged;
+	WIN_WinPAINT = GAPI_WinPAINT;
+	HandleMessage = DIB_HandleMessage; 
+
+	device->free = GAPI_DeleteDevice;
+
+	/* Load gapi library */
+#define gx device->hidden->gxFunc
+
+    LINK( GXOpenDisplay, gx.GXOpenDisplay,         "?GXOpenDisplay@@YAHPAUHWND__@@K@Z" )
+    LINK( GXCloseDisplay, gx.GXCloseDisplay,        "?GXCloseDisplay@@YAHXZ" )
+    LINK( GXBeginDraw, gx.GXBeginDraw,           "?GXBeginDraw@@YAPAXXZ" )
+    LINK( GXEndDraw, gx.GXEndDraw,             "?GXEndDraw@@YAHXZ" )
+    LINK( GXOpenInput, gx.GXOpenInput,           "?GXOpenInput@@YAHXZ" )
+    LINK( GXCloseInput, gx.GXCloseInput,          "?GXCloseInput@@YAHXZ" )
+    LINK( GXGetDisplayProperties, gx.GXGetDisplayProperties,"?GXGetDisplayProperties@@YA?AUGXDisplayProperties@@XZ" )
+    LINK( GXGetDefaultKeys, gx.GXGetDefaultKeys,      "?GXGetDefaultKeys@@YA?AUGXKeyList@@H@Z" )
+    LINK( GXSuspend, gx.GXSuspend,             "?GXSuspend@@YAHXZ" )
+    LINK( GXResume, gx.GXResume,              "?GXResume@@YAHXZ" )
+    LINK( GXSetViewport, gx.GXSetViewport,         "?GXSetViewport@@YAHKKKK@Z" )
+    LINK( GXIsDisplayDRAMBuffer, gx.GXIsDisplayDRAMBuffer, "?GXIsDisplayDRAMBuffer@@YAHXZ" )
+
+	/* wrong gapi.dll */
+	if( !gx.GXOpenDisplay )
+	{
+		if( g_hGapiLib ) 
+		{
+			FreeLibrary(g_hGapiLib);
+			g_hGapiLib = 0;
+		}
+	}
+	
+	if( !gx.GXOpenDisplay && !g_bRawBufferAvailable)
+	{
+		SDL_SetError("Error: damaged or unknown gapi.dll!\n");
+		GAPI_DeleteDevice(device);
+		return 0;
+	}
+
+	return device;
+}
+
+VideoBootStrap GAPI_bootstrap = {
+	GAPIVID_DRIVER_NAME, "WinCE GAPI video driver",
+	GAPI_Available, GAPI_CreateDevice
+};
+
+static void FillStructs(_THIS, BOOL useVga)
+{
+#ifdef _ARM_
+	WCHAR oemstr[100];
+#endif
+	/* fill a device properties */
+
+	if( !useVga )
+	{
+		this->hidden->gxProperties = this->hidden->gxFunc.GXGetDisplayProperties();
+		this->hidden->needUpdate = 1;
+		this->hidden->hiresFix = 0;
+		this->hidden->useVga = 0;
+#ifdef _ARM_
+		/* check some devices and extract addition info */
+		SystemParametersInfo( SPI_GETOEMINFO, sizeof( oemstr ), oemstr, 0 );
+
+		// buggy iPaq38xx
+		if ((oemstr[12] == 'H') && (oemstr[13] == '3') && (oemstr[14] == '8') && (this->hidden->gxProperties.cbxPitch > 0)) 
+		{
+			this->hidden->videoMem = (PIXEL*)0xac0755a0;
+			this->hidden->gxProperties.cbxPitch = -640;
+			this->hidden->gxProperties.cbyPitch = 2;
+			this->hidden->needUpdate = 0;
+		}
+#endif
+	} else
+	{
+	    this->hidden->needUpdate = 0;		
+		this->hidden->hiresFix = 0;
+		this->hidden->gxProperties.cBPP = g_RawFrameBufferInfo.wBPP;
+		this->hidden->gxProperties.cbxPitch = g_RawFrameBufferInfo.cxStride;
+		this->hidden->gxProperties.cbyPitch = g_RawFrameBufferInfo.cyStride;
+		this->hidden->gxProperties.cxWidth = g_RawFrameBufferInfo.cxPixels;
+		this->hidden->gxProperties.cyHeight = g_RawFrameBufferInfo.cyPixels;
+		this->hidden->videoMem = g_RawFrameBufferInfo.pFramePointer;
+		this->hidden->useVga = 1;
+
+		switch( g_RawFrameBufferInfo.wFormat )
+		{
+		case FORMAT_565:
+			this->hidden->gxProperties.ffFormat = kfDirect565;
+			break;
+		case FORMAT_555:
+			this->hidden->gxProperties.ffFormat = kfDirect555;
+			break;
+		default:
+			/* unknown pixel format, try define by BPP! */
+			switch( g_RawFrameBufferInfo.wBPP )
+			{
+			case 4:
+			case 8:
+				this->hidden->gxProperties.ffFormat = kfDirect;
+			case 16:
+				this->hidden->gxProperties.ffFormat = kfDirect565;
+			default:
+				this->hidden->gxProperties.ffFormat = kfDirect;
+				break;
+			}
+		}
+	}
+
+	if( this->hidden->gxProperties.cBPP != 16 )
+	{
+		this->hidden->gapiOrientation = SDL_ORIENTATION_UP;
+	} else
+	if( (this->hidden->gxProperties.cbxPitch > 0) && (this->hidden->gxProperties.cbyPitch > 0 ))
+	{
+		this->hidden->gapiOrientation = SDL_ORIENTATION_UP;
+	} else
+	if( (this->hidden->gxProperties.cbxPitch > 0) && (this->hidden->gxProperties.cbyPitch < 0 ))
+	{
+		this->hidden->gapiOrientation = SDL_ORIENTATION_RIGHT; // ipaq 3660
+	} else
+	if( (this->hidden->gxProperties.cbxPitch < 0) && (this->hidden->gxProperties.cbyPitch > 0 ))
+	{
+		this->hidden->gapiOrientation = SDL_ORIENTATION_LEFT; // ipaq 3800
+	}
+}
+
+static void GAPI_CreatePalette(int ncolors, SDL_Color *colors)
+{
+  // Setup a custom color palette
+   BYTE buffer[ sizeof(LOGPALETTE) + 255 * sizeof(PALETTEENTRY) ];
+   int i;
+   LOGPALETTE*   pLogical = (LOGPALETTE*)buffer;
+   PALETTEENTRY* entries  = pLogical->palPalEntry;
+   HPALETTE hPalette;
+   HDC hdc;
+
+   for (i = 0; i < ncolors; ++i)
+   {
+      // Find intensity by replicating the bit patterns over a byte
+      entries[i].peRed   = colors[i].r;
+      entries[i].peGreen = colors[i].g;
+      entries[i].peBlue  = colors[i].b;
+      entries[i].peFlags = 0;
+   }
+
+   // Create the GDI palette object
+   pLogical->palVersion    = 0x0300;
+   pLogical->palNumEntries = ncolors;
+
+   hPalette = CreatePalette( pLogical );
+   ASSERT(hPalette);
+	
+
+   // Realize the palette
+   hdc = GetDC(0);
+
+   SelectPalette( hdc, hPalette, FALSE );
+   RealizePalette( hdc );
+
+   ReleaseDC( 0, hdc );
+   DeleteObject( hPalette );
+}
+
+int GAPI_VideoInit(_THIS, SDL_PixelFormat *vformat)
+{
+	int i,bpp;
+
+	/* Create the window */
+	if ( DIB_CreateWindow(this) < 0 ) {
+		return(-1);
+	}
+
+	if( g_hGapiLib )
+	{
+		FillStructs(this, 0);
+
+		// SDL does not supports 2/4bpp mode, so use 16 bpp
+		bpp = gapi->gxProperties.cBPP < 8 ? 16 : gapi->gxProperties.cBPP;
+		
+		/* set up normal and landscape mode */
+		GAPI_AddMode(this, bpp, gapi->gxProperties.cyHeight, gapi->gxProperties.cxWidth);	
+		GAPI_AddMode(this, bpp, gapi->gxProperties.cxWidth, gapi->gxProperties.cyHeight);	
+	}
+
+	/* add hi-res mode */
+	if( g_bRawBufferAvailable && 
+		!((gapi->gxProperties.cxWidth == (unsigned)g_RawFrameBufferInfo.cxPixels) && (gapi->gxProperties.cyHeight == (unsigned)g_RawFrameBufferInfo.cyPixels)))
+	{
+		FillStructs(this, 1);
+
+		// SDL does not supports 2/4bpp mode, so use 16 bpp
+		bpp = gapi->gxProperties.cBPP < 8 ? 16 : gapi->gxProperties.cBPP;
+
+		/* set up normal and landscape mode */
+		GAPI_AddMode(this, bpp, gapi->gxProperties.cyHeight, gapi->gxProperties.cxWidth);	
+		GAPI_AddMode(this, bpp, gapi->gxProperties.cxWidth, gapi->gxProperties.cyHeight);	
+	}
+
+	/* Sort the mode lists */
+	for ( i=0; i<NUM_MODELISTS; ++i ) {
+		if ( gapi->SDL_nummodes[i] > 0 ) {
+			qsort(gapi->SDL_modelist[i], gapi->SDL_nummodes[i], sizeof *gapi->SDL_modelist[i], cmpmodes);
+		}
+	}
+
+	vformat->BitsPerPixel = this->hidden->gxProperties.cBPP < 8 ? 16 : (unsigned char)this->hidden->gxProperties.cBPP;
+
+	// Get color mask
+	if (this->hidden->gxProperties.ffFormat & kfDirect565) {
+		vformat->BitsPerPixel = 16;
+		vformat->Rmask = 0x0000f800;
+		vformat->Gmask = 0x000007e0;
+		vformat->Bmask = 0x0000001f;
+		this->hidden->videoMode = GAPI_DIRECT_565;
+	}
+	else
+	if (this->hidden->gxProperties.ffFormat & kfDirect555) {
+		vformat->BitsPerPixel = 16;
+		vformat->Rmask = 0x00007c00;
+		vformat->Gmask = 0x000003e0;
+		vformat->Bmask = 0x0000001f;
+		this->hidden->videoMode = GAPI_DIRECT_555;
+	}
+	else
+	if ((this->hidden->gxProperties.ffFormat & kfDirect) && (this->hidden->gxProperties.cBPP < 8)) {
+		// We'll perform the conversion
+		vformat->BitsPerPixel = 16;
+		vformat->Rmask = 0x0000f800; // 16 bit 565
+		vformat->Gmask = 0x000007e0;
+		vformat->Bmask = 0x0000001f;
+		if (this->hidden->gxProperties.ffFormat & kfDirectInverted)
+			this->hidden->invert = (1 << this->hidden->gxProperties.cBPP) - 1;
+		this->hidden->colorscale = this->hidden->gxProperties.cBPP < 8 ? 8 - this->hidden->gxProperties.cBPP : 0;
+		this->hidden->videoMode = GAPI_MONO;
+	}
+	else
+	if (this->hidden->gxProperties.ffFormat & kfPalette) {
+		this->hidden->videoMode = GAPI_PALETTE;
+	} 
+
+	/* We're done! */
+	return(0);
+}
+
+SDL_Rect **GAPI_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
+{
+	return(this->hidden->SDL_modelist[((format->BitsPerPixel+7)/8)-1]);
+//  	 return (SDL_Rect **) -1;
+}
+
+SDL_Surface *GAPI_SetVideoMode(_THIS, SDL_Surface *current,
+				int width, int height, int bpp, Uint32 flags)
+{
+	SDL_Surface *video; 
+	Uint32 Rmask, Gmask, Bmask; 
+	DWORD style; 
+	SDL_Rect allScreen;
+
+	if( bpp < 4 )
+	{
+		SDL_SetError("1 bpp and 2 bpp modes is not implemented yet!");
+		return 0;
+	}
+
+	/* Recalculate bitmasks if necessary */
+	if (bpp == current->format->BitsPerPixel) {
+		video = current;
+	}
+	else {
+		switch(bpp) {
+			case 8:
+				Rmask = 0;
+				Gmask = 0;
+				Bmask = 0;
+				break;
+			case 15:				
+			case 16:
+				/* Default is 565 unless the display is specifically 555 */
+				if (this->hidden->gxProperties.ffFormat & kfDirect555) {
+					Rmask = 0x00007c00;
+					Gmask = 0x000003e0;
+					Bmask = 0x0000001f;
+				}
+				else {
+					Rmask = 0x0000f800;
+					Gmask = 0x000007e0;
+					Bmask = 0x0000001f;
+				}
+				break;
+			case 24:
+			case 32:
+				Rmask = 0x00ff0000;
+				Gmask = 0x0000ff00;
+				Bmask = 0x000000ff;
+				break;
+			default:
+				SDL_SetError("Unsupported Bits Per Pixel format requested");
+				return NULL;
+		}
+		video = SDL_CreateRGBSurface(SDL_SWSURFACE,
+					0, 0, bpp, Rmask, Gmask, Bmask, 0);
+		if ( video == NULL ) {
+			SDL_OutOfMemory();
+			return(NULL);
+		}
+	}
+
+	gapi->userOrientation = SDL_ORIENTATION_UP;
+	video->flags = SDL_FULLSCREEN;	/* Clear flags, GAPI supports fullscreen only */
+
+	/* GAPI or VGA? */
+	if( g_hGapiLib )
+	{
+		FillStructs(this, 0);
+		if( (((unsigned)width != gapi->gxProperties.cxWidth) || ((unsigned)height != gapi->gxProperties.cyHeight))
+			&& (((unsigned)width != gapi->gxProperties.cyHeight) || ((unsigned)height != gapi->gxProperties.cxWidth)))
+			FillStructs(this, 1); // gapi is found but we use VGA resolution			
+	} else
+		FillStructs(this, 1);
+
+	if ( !this->hidden->needUpdate && !this->hidden->videoMem) {
+		SDL_SetError("Couldn't get address of video memory, may be unsupported device or bug");
+		return(NULL);
+	}
+
+	/* detect landscape mode */
+	if( (width > height) && (GetSystemMetrics(SM_CXSCREEN) < GetSystemMetrics(SM_CYSCREEN))) 
+		gapi->userOrientation = SDL_ORIENTATION_RIGHT;
+
+	/* shall we apply hires fix? for example when we do not use hires resource */
+	gapi->hiresFix = 0;
+	if( gapi->userOrientation == SDL_ORIENTATION_RIGHT )
+	{
+		if( (width > GetSystemMetrics(SM_CYSCREEN)) || (height > GetSystemMetrics(SM_CXSCREEN)))
+			gapi->hiresFix = 1;
+	} else
+		if( (width > GetSystemMetrics(SM_CXSCREEN)) || (height > GetSystemMetrics(SM_CYSCREEN)))
+			gapi->hiresFix = 1;
+
+	switch( gapi->userOrientation )
+	{
+	case SDL_ORIENTATION_UP:
+		gapi->startOffset = 0;
+		gapi->dstLineStep = gapi->gxProperties.cbyPitch;
+		gapi->dstPixelStep = gapi->gxProperties.cbxPitch;
+		break;
+	case SDL_ORIENTATION_RIGHT:
+		switch( gapi->gapiOrientation )
+		{
+		case SDL_ORIENTATION_UP:
+		case SDL_ORIENTATION_RIGHT:
+		case SDL_ORIENTATION_LEFT:
+			if( (this->hidden->videoMode == GAPI_MONO) )
+				gapi->startOffset = -gapi->gxProperties.cbxPitch + 1; // monochrome mode
+			else
+				gapi->startOffset = gapi->gxProperties.cbyPitch * (gapi->gxProperties.cyHeight - 1);
+				
+			gapi->dstLineStep = gapi->gxProperties.cbxPitch;
+			gapi->dstPixelStep = -gapi->gxProperties.cbyPitch;
+			break;
+		}
+	}
+
+	video->w = this->hidden->w = width;
+	video->h = this->hidden->h = height;
+	video->pitch = SDL_CalculatePitch(video); 
+
+	/* Small fix for WinCE/Win32 - when activating window
+	   SDL_VideoSurface is equal to zero, so activating code
+	   is not called properly for fullscreen windows because
+	   macros WINDIB_FULLSCREEN uses SDL_VideoSurface
+	*/
+	SDL_VideoSurface = video;
+
+	/* GAPI is always fullscreen, title bar is useless */
+	style = 0;
+
+	if (!SDL_windowid)
+		SetWindowLong(SDL_Window, GWL_STYLE, style);
+ 
+	/* Allocate bitmap */
+	if(gapiBuffer) 
+	{
+		free(gapiBuffer);
+		gapiBuffer = NULL;
+	}
+	gapiBuffer = malloc(video->h * video->pitch);
+	video->pixels = gapiBuffer; 
+
+	if ( ! this->hidden->buffer ) {
+		SDL_SetError("Couldn't allocate buffer for requested mode");
+		return(NULL);
+	}
+
+	memset(gapiBuffer, 255, video->h * video->pitch);
+	MoveWindow(SDL_Window, 0, 0, GetSystemMetrics(SM_CXSCREEN), GetSystemMetrics(SM_CYSCREEN), FALSE);
+	ShowWindow(SDL_Window, SW_SHOW);
+	SetForegroundWindow(SDL_Window);
+
+#if REPORT_VIDEO_INFO
+	printf("Video properties:\n");
+	printf("display bpp: %d\n", gapi->gxProperties.cBPP);
+	printf("display width: %d\n", gapi->gxProperties.cxWidth);
+	printf("display height: %d\n", gapi->gxProperties.cyHeight);
+	printf("x pitch: %d\n", gapi->gxProperties.cbxPitch);
+	printf("y pitch: %d\n", gapi->gxProperties.cbyPitch);
+	printf("gapi flags: 0x%x\n", gapi->gxProperties.ffFormat);
+	printf("video memory: 0x%x\n", gapi->videoMem);
+	printf("need update: %d\n", gapi->needUpdate);
+	printf("hi-res fix: %d\n", gapi->hiresFix);
+	printf("VGA is available on the device: %d\n", g_bRawBufferAvailable);
+	printf("use VGA resolution: %d\n", gapi->useVga);
+	printf("video surface bpp: %d\n", video->format->BitsPerPixel);
+	printf("video surface width: %d\n", video->w);
+	printf("video surface height: %d\n", video->h);
+#endif
+
+	/* Open GAPI display */
+	if( !gapi->useVga )
+		if( !gapi->gxFunc.GXOpenDisplay(SDL_Window, GX_FULLSCREEN) )
+		{
+			SDL_SetError("Couldn't initialize GAPI");
+			return(NULL);
+		}
+ 
+	/* Blank screen */
+	allScreen.x = allScreen.y = 0;
+	allScreen.w = video->w - 1;
+	allScreen.h = video->h - 1;
+	GAPI_UpdateRects(this, 1, &allScreen);
+
+	/* We're done */
+	return(video);
+}
+
+/* We don't actually allow hardware surfaces other than the main one */
+static int GAPI_AllocHWSurface(_THIS, SDL_Surface *surface)
+{
+	return(-1);
+}
+static void GAPI_FreeHWSurface(_THIS, SDL_Surface *surface)
+{
+	return;
+}
+
+/* We need to wait for vertical retrace on page flipped displays */
+static int GAPI_LockHWSurface(_THIS, SDL_Surface *surface)
+{
+	return(0);
+}
+
+static void GAPI_UnlockHWSurface(_THIS, SDL_Surface *surface)
+{
+	return;
+}
+
+static int updateLine8to8(_THIS, unsigned char *srcPointer, unsigned char *destPointer, int width, int height, int lines)
+{
+	if( gapi->dstPixelStep == 1) /* optimized blitting on most devices */
+	{
+		memcpy(destPointer, srcPointer, width);
+		return 1;
+	} else
+	{
+		// TODO: read 4 pixels, write DWORD
+		int step = gapi->dstPixelStep;
+		while(width--)
+		{
+			*destPointer = *srcPointer++;
+			destPointer += step;
+		}
+	}
+	return 1;
+}
+
+/* Video memory is very slow so lets optimize as much as possible */
+static int updateLine16to16(_THIS, PIXEL *srcPointer, PIXEL *destPointer, int width, int height, int lines)
+{
+	PIXEL *line1, *line2;
+	int step = gapi->dstPixelStep / 2;
+
+	if( step == 1 ) /* optimized blitting on most devices */
+	{
+		memcpy(destPointer, srcPointer, width * sizeof(PIXEL));
+		return 1;
+	}
+	else
+	{
+		if( (gapi->gapiOrientation != SDL_ORIENTATION_UP) &&
+			(gapi->userOrientation == SDL_ORIENTATION_UP )) // iPaq 3660/3800 and user orientation up
+		{	
+			// to prevent data misalignment copy only one line
+			if( ((((unsigned)destPointer & 3) != 0) && (gapi->gapiOrientation == SDL_ORIENTATION_LEFT)) 
+				|| ((((unsigned)destPointer & 3) == 0) && (gapi->gapiOrientation != SDL_ORIENTATION_LEFT))
+				|| (lines == 1) ) 
+			{
+				while(width--)
+				{
+					*destPointer = *srcPointer++;
+					destPointer += step;
+				}
+				return 1;
+			}
+
+			/* read two lines at the same time, write DWORD */
+			line1 = srcPointer;
+			line2 = srcPointer + SDL_VideoSurface->pitch / 2;
+
+			if( gapi->gapiOrientation == SDL_ORIENTATION_LEFT )
+				while(width--) // iPaq 3800
+				{
+					*(DWORD*)destPointer =(*line2++ << 16) | *line1++;
+					destPointer += step;
+				}
+			else
+			{
+				destPointer += gapi->gxProperties.cbyPitch / 2;
+				while(width--) // iPaq 3660
+				{
+					*(DWORD*)destPointer =(*line1++ << 16) | *line2++;
+					destPointer += step;
+				}
+			}
+			return 2;
+		} else
+		{
+			// iPaq 3800 and user orientation landscape
+			if( gapi->gapiOrientation == SDL_ORIENTATION_LEFT )
+			{
+				int w1;
+
+				// to prevent data misalignment copy only one pixel
+				if( (((unsigned)destPointer & 3) == 0) && (width > 0)) 
+				{
+					*destPointer-- = *srcPointer++;
+					width--;
+				}
+
+				destPointer--;
+
+				w1 = width / 2;
+
+				while(w1--)
+				{
+					DWORD p = *(DWORD*)srcPointer;
+					*((DWORD*)destPointer) = (p << 16) | (p >> 16);
+					destPointer -= 2;
+					srcPointer += 2;
+				}
+
+				if( width & 1 ) // copy the last pixel
+				{
+					destPointer++;
+					*destPointer = *srcPointer;
+				}
+
+				return 1;
+			}
+
+			// modern iPaqs and user orientation landscape
+			// read two pixels, write DWORD
+
+			line1 = srcPointer;
+			line2 = srcPointer + SDL_VideoSurface->pitch / 2;
+
+			if( (((unsigned)destPointer & 3) != 0) || (lines == 1) ) 
+			{
+				while(width--)
+				{
+					*destPointer = *srcPointer++;
+					destPointer += step;
+				}
+				return 1;
+			}
+			
+			while(width--)
+			{
+				*(DWORD*)destPointer =(*line2++ << 16) | *line1++;
+				destPointer -= gapi->gxProperties.cbyPitch / 2;
+			}
+			return 2;
+		}
+	}
+}
+
+// Color component masks for 565
+#define REDMASK (31<<11)
+#define GREENMASK (63<<5)
+#define BLUEMASK (31)
+
+
+static int updateLine16to4(_THIS, PIXEL *srcPointer, unsigned char *destPointer, int width, int height, int lines, int yNibble, int xNibble)
+{
+	PIXEL *line1, *line2;
+	int step = gapi->dstPixelStep;
+
+	if( gapi->userOrientation == SDL_ORIENTATION_UP )
+	{
+		if( yNibble ) // copy bottom half of a line
+		{
+			while(width--)
+			{
+				PIXEL c1 = *srcPointer++;
+				c1 = ((c1 & REDMASK) >> 11) + ((c1 & GREENMASK) >> 5) + (c1 & BLUEMASK);			
+				*destPointer = (*destPointer & 0x0F) | ((~(c1 >> 3) << 4));
+				destPointer += step;
+			}
+			return 1;
+		}
+
+		// either 1 pixel picture or tail, anyway this is the last line
+		if( lines == 1 )
+		{
+			while(width--)
+			{
+				PIXEL c1 = *srcPointer++;
+				c1 = ((c1 & REDMASK) >> 11) + ((c1 & GREENMASK) >> 5) + (c1 & BLUEMASK);			
+				*destPointer = (*destPointer & 0xF0) | ((~(c1 >> 3) & 0xF));
+				destPointer += step;
+			}
+			return 1;
+		}
+
+		line1 = srcPointer;
+		line2 = srcPointer + SDL_VideoSurface->pitch / 2;
+
+		while(width--)
+		{
+			PIXEL c1 = *line1++;
+			PIXEL c2 = *line2++;
+			c1 = ((c1 & REDMASK) >> 11) + ((c1 & GREENMASK) >> 5) + (c1 & BLUEMASK);
+			c2 = ((c2 & REDMASK) >> 11) + ((c2 & GREENMASK) >> 5) + (c2 & BLUEMASK);
+			*destPointer = ~((c1 >> 3) + ((c2 >> 3) << 4));
+			destPointer += step;
+		}
+		return 2;
+	} else
+	{
+		int w1;
+		w1 = width / 2;
+
+		if( xNibble )
+		{
+			// copy one pixel
+			PIXEL c1 = *srcPointer++;
+			c1 = ((c1 & REDMASK) >> 11) + ((c1 & GREENMASK) >> 5) + (c1 & BLUEMASK);			
+			*destPointer = (*destPointer & 0xF0) | ((~(c1 >> 3) & 0xF));
+			destPointer++;
+		}
+
+		while(w1--)
+		{
+			PIXEL c1 = *srcPointer;
+			PIXEL c2 = *(srcPointer + 1);
+			c1 = ((c1 & REDMASK) >> 11) + ((c1 & GREENMASK) >> 5) + (c1 & BLUEMASK);
+			c2 = ((c2 & REDMASK) >> 11) + ((c2 & GREENMASK) >> 5) + (c2 & BLUEMASK);
+			*destPointer++ = ~((c2 >> 3) + ((c1 >> 3) << 4));
+			srcPointer += 2;
+		}
+
+		// copy tail
+		if( (width & 1) && !xNibble )
+		{
+			PIXEL c1 = *srcPointer;
+			c1 = ((c1 & REDMASK) >> 11) + ((c1 & GREENMASK) >> 5) + (c1 & BLUEMASK);			
+			*destPointer = (*destPointer & 0x0F) | ((~(c1 >> 3) << 4));
+		}
+
+		return 1;
+	}
+}
+
+static void GAPI_UpdateRectsMono(_THIS, int numrects, SDL_Rect *rects)
+{
+	int i, height;
+	int linesProcessed;
+	int xNibble, yNibble;
+
+	for (i=0; i<numrects; i++)
+	{
+		unsigned char *destPointer;
+		unsigned char *srcPointer;
+
+		if( gapi->userOrientation == SDL_ORIENTATION_UP )
+			destPointer = (unsigned char*) gapi->videoMem + gapi->startOffset - rects[i].y * gapi->gxProperties.cBPP / 8 + rects[i].x * gapi->dstPixelStep;
+		else
+			destPointer = (unsigned char*) gapi->videoMem + gapi->startOffset + rects[i].x * gapi->gxProperties.cBPP / 8 + rects[i].y * gapi->dstLineStep;
+
+		srcPointer = ((unsigned char*) SDL_VideoSurface->pixels) + rects[i].y * SDL_VideoSurface->pitch + rects[i].x * 2;
+		yNibble = rects[i].y & 1; // TODO: only for 4 bpp
+		xNibble = rects[i].x & 1;
+		height = rects[i].h;
+		while (height > 0)
+		{
+			switch(gapi->gxProperties.cBPP)
+			{
+			case 2: // TODO
+			case 4:
+					linesProcessed = updateLine16to4(this, (PIXEL*) srcPointer, destPointer, rects[i].w, rects[i].h, height, yNibble, xNibble);
+					yNibble = 0;
+			}
+			height -= linesProcessed;
+			if( gapi->userOrientation == SDL_ORIENTATION_UP )
+				destPointer--; // always fill 1 byte
+			else destPointer += gapi->dstLineStep;
+			srcPointer += SDL_VideoSurface->pitch * linesProcessed; // pitch in bytes
+		}
+	}
+}
+
+static void GAPI_UpdateRectsColor(_THIS, int numrects, SDL_Rect *rects)
+{
+	int i, height;
+	int bytesPerPixel = (gapi->gxProperties.cBPP + 1) / 8;
+	int linesProcessed;
+	for (i=0; i<numrects; i++) {
+		unsigned char *destPointer = (unsigned char*) gapi->videoMem + gapi->startOffset + rects[i].y * gapi->dstLineStep + rects[i].x * gapi->dstPixelStep;
+		unsigned char *srcPointer = ((unsigned char*) SDL_VideoSurface->pixels) + rects[i].y * SDL_VideoSurface->pitch + rects[i].x * bytesPerPixel;
+		height = rects[i].h;
+
+//		fprintf(stderr, "Starting rect %dx%d, dst=0x%x, w = %d, h = %d\n", rects[i].w, rects[i].h,destPointer,rects[i].w,rects[i].h);
+//		fflush(stderr);
+		linesProcessed = height;
+
+		while (height > 0) {
+			switch(bytesPerPixel)
+			{
+			case 1:
+				linesProcessed = updateLine8to8(this, srcPointer, (unsigned char *) destPointer, rects[i].w, rects[i].h, height);
+				break;
+			case 2:
+#pragma warning(disable: 4133)
+				linesProcessed = updateLine16to16(this, (PIXEL*) srcPointer, destPointer, rects[i].w, rects[i].h, height);
+				break;
+			}
+			height -= linesProcessed;
+			destPointer += gapi->dstLineStep * linesProcessed;
+			srcPointer += SDL_VideoSurface->pitch * linesProcessed; // pitch in bytes
+		}
+//		fprintf(stderr, "End of rect\n");
+//		fflush(stderr);
+	}
+}
+
+
+static void GAPI_UpdateRects(_THIS, int numrects, SDL_Rect *rects)
+{
+	if( gapi->needUpdate )
+		gapi->videoMem = gapi->gxFunc.GXBeginDraw(); 
+
+	if( gapi->gxProperties.cBPP < 8 )
+		GAPI_UpdateRectsMono(this, numrects, rects);
+	else
+		GAPI_UpdateRectsColor(this, numrects, rects);
+
+	if( gapi->needUpdate )
+		gapi->gxFunc.GXEndDraw();
+}
+
+static void FlushMessageQueue()
+{
+	MSG  msg;
+	while ( PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) ) {
+		if ( msg.message == WM_QUIT ) break;
+		TranslateMessage( &msg );
+		DispatchMessage( &msg );
+	}
+}
+
+
+/* Note:  If we are terminated, this could be called in the middle of
+   another SDL video routine -- notably UpdateRects.
+*/
+void GAPI_VideoQuit(_THIS)
+{
+	int i, j;
+	/* Destroy the window and everything associated with it */
+	if ( SDL_Window ) 
+	{
+	    if ((g_hGapiLib != 0) && this && this->hidden && this->hidden->gxFunc.GXCloseDisplay && !this->hidden->useVga)
+			this->hidden->gxFunc.GXCloseDisplay(); 
+
+		if (this->screen->pixels != NULL)
+		{
+			free(this->screen->pixels);
+			this->screen->pixels = NULL;
+		}
+		if ( screen_icn ) {
+			DestroyIcon(screen_icn);
+			screen_icn = NULL;
+		}
+
+		DIB_DestroyWindow(this);
+		SDL_UnregisterApp();
+		FlushMessageQueue();
+
+		SDL_Window = NULL;
+#if defined(_WIN32_WCE)
+
+// Unload wince aygshell library to prevent leak
+		if( aygshell ) 
+		{
+			FreeLibrary(aygshell);
+			aygshell = NULL;
+		}
+#endif
+
+	/* Free video mode lists */
+	for ( i=0; i<NUM_MODELISTS; ++i ) {
+		if ( gapi->SDL_modelist[i] != NULL ) {
+			for ( j=0; gapi->SDL_modelist[i][j]; ++j )
+				free(gapi->SDL_modelist[i][j]);
+			free(gapi->SDL_modelist[i]);
+			gapi->SDL_modelist[i] = NULL;
+		}
+	}
+
+	}
+
+}
+
+static void GAPI_RealizePalette(_THIS)
+{
+	OutputDebugString(TEXT("GAPI_RealizePalette NOT IMPLEMENTED !\r\n"));
+}
+
+static void GAPI_PaletteChanged(_THIS, HWND window)
+{
+	OutputDebugString(TEXT("GAPI_PaletteChanged NOT IMPLEMENTED !\r\n"));
+}
+
+/* Exported for the windows message loop only */
+static void GAPI_WinPAINT(_THIS, HDC hdc)
+{
+	OutputDebugString(TEXT("GAPI_WinPAINT NOT IMPLEMENTED !\r\n"));
+}
+
+int GAPI_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors) 
+{
+	GAPI_CreatePalette(ncolors, colors);
+	return 1;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/gapi/SDL_gapivideo.h	Thu Jan 19 08:43:00 2006 +0000
@@ -0,0 +1,164 @@
+/*
+    SDL - Simple DirectMedia Layer
+    Copyright (C) 1997-2004 Sam Lantinga
+
+    This library is free software; you can redistribute it and/or
+    modify it under the terms of the GNU Library General Public
+    License as published by the Free Software Foundation; either
+    version 2 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
+    Library General Public License for more details.
+
+    You should have received a copy of the GNU Library General Public
+    License along with this library; if not, write to the Free
+    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+
+    Sam Lantinga
+    slouken@libsdl.org
+*/
+
+#ifdef SAVE_RCSID
+static char rcsid =
+ "@(#) $Id$";
+#endif
+
+#ifndef _SDL_gapivideo_h
+#define _SDL_gapivideo_h
+
+#include "SDL_mouse.h"
+#include "SDL_sysvideo.h"
+#include "SDL_mutex.h"
+
+/* From gx.h, since it's not really C compliant */
+
+struct GXDisplayProperties {
+    DWORD cxWidth;
+    DWORD cyHeight;         // notice lack of 'th' in the word height.
+    long cbxPitch;          // number of bytes to move right one x pixel - can be negative.
+    long cbyPitch;          // number of bytes to move down one y pixel - can be negative.
+    long cBPP;              // # of bits in each pixel
+    DWORD ffFormat;         // format flags.
+};
+
+struct GXKeyList {
+    short vkUp;             // key for up
+    POINT ptUp;             // x,y position of key/button.  Not on screen but in screen coordinates.
+    short vkDown;
+    POINT ptDown;
+    short vkLeft;
+    POINT ptLeft;
+    short vkRight;
+    POINT ptRight;
+    short vkA;
+    POINT ptA;
+    short vkB;
+    POINT ptB;
+    short vkC;
+    POINT ptC;
+    short vkStart;
+    POINT ptStart;
+};
+
+typedef int   (*PFNGXOpenDisplay)(HWND hWnd, DWORD dwFlags);
+typedef int   (*PFNGXCloseDisplay)();
+typedef void* (*PFNGXBeginDraw)();
+typedef int   (*PFNGXEndDraw)();
+typedef int   (*PFNGXOpenInput)();
+typedef int   (*PFNGXCloseInput)();
+typedef struct GXDisplayProperties (*PFNGXGetDisplayProperties)();
+typedef struct GXKeyList (*PFNGXGetDefaultKeys)(int iOptions);
+typedef int   (*PFNGXSuspend)();
+typedef int   (*PFNGXResume)();
+typedef int   (*PFNGXSetViewport)( DWORD dwTop, DWORD dwHeight, DWORD dwReserved1, DWORD dwReserved2 );
+typedef BOOL  (*PFNGXIsDisplayDRAMBuffer)();
+
+struct GapiFunc
+{
+    PFNGXOpenDisplay          GXOpenDisplay;
+    PFNGXCloseDisplay         GXCloseDisplay;
+    PFNGXBeginDraw            GXBeginDraw;
+    PFNGXEndDraw              GXEndDraw;
+    PFNGXOpenInput            GXOpenInput;
+    PFNGXCloseInput           GXCloseInput;
+    PFNGXGetDisplayProperties GXGetDisplayProperties;
+    PFNGXGetDefaultKeys       GXGetDefaultKeys;
+    PFNGXSuspend              GXSuspend;
+    PFNGXResume               GXResume;
+    PFNGXSetViewport          GXSetViewport;
+    PFNGXIsDisplayDRAMBuffer  GXIsDisplayDRAMBuffer;
+};
+
+#define kfLandscape	0x8			// Screen is rotated 270 degrees
+#define kfPalette	0x10		// Pixel values are indexes into a palette
+#define kfDirect	0x20		// Pixel values contain actual level information
+#define kfDirect555	0x40		// 5 bits each for red, green and blue values in a pixel.
+#define kfDirect565	0x80		// 5 red bits, 6 green bits and 5 blue bits per pixel
+#define kfDirect888	0x100		// 8 bits each for red, green and blue values in a pixel.
+#define kfDirect444	0x200		// 4 red, 4 green, 4 blue
+#define kfDirectInverted 0x400
+
+#define GX_FULLSCREEN	0x01		// for OpenDisplay() 
+#define GX_NORMALKEYS   0x02
+#define GX_LANDSCAPEKEYS        0x03
+
+typedef enum
+{
+	SDL_ORIENTATION_UP,
+	SDL_ORIENTATION_DOWN,
+	SDL_ORIENTATION_LEFT,
+	SDL_ORIENTATION_RIGHT
+} SDL_ScreenOrientation;
+
+/* GAPI video mode */
+typedef enum {
+	GAPI_NONE = 0,
+	GAPI_DIRECT_565,
+	GAPI_DIRECT_555,
+	GAPI_MONO,
+	GAPI_PALETTE
+} GAPIVideoMode; 
+
+/* Hidden "this" pointer for the video functions */
+#define _THIS	SDL_VideoDevice *this
+
+typedef unsigned short PIXEL;
+
+/* Private display data 
+   begin with DIB private structure to allow DIB events code sharing
+*/
+struct SDL_PrivateVideoData {
+    HBITMAP screen_bmp;
+    HPALETTE screen_pal;
+
+#define NUM_MODELISTS	4		/* 8, 16, 24, and 32 bits-per-pixel */
+    int SDL_nummodes[NUM_MODELISTS];
+    SDL_Rect **SDL_modelist[NUM_MODELISTS];
+	enum SDL_ScreenOrientation userOrientation;
+	int invert;
+	char hiresFix; // using hires mode without defining hires resource
+// --------------
+    int w, h;
+	enum SDL_ScreenOrientation gapiOrientation;
+
+    void *buffer; // may be 8, 16, 24, 32 bpp
+	PIXEL *videoMem;
+	BOOL needUpdate;
+	struct GXKeyList keyList;
+	struct GapiFunc gxFunc;
+	struct GXDisplayProperties gxProperties;
+	enum GAPIVideoMode videoMode;
+	int colorscale;
+	int dstLineStep;  // in bytes
+	int dstPixelStep; // in bytes
+	int startOffset; // in bytes
+	int useVga;
+};
+
+
+#define gapiBuffer this->hidden->buffer
+#define gapi this->hidden
+
+#endif /* _SDL_gapivideo_h */
--- a/src/video/wincommon/SDL_lowvideo.h	Thu Jan 19 08:36:41 2006 +0000
+++ b/src/video/wincommon/SDL_lowvideo.h	Thu Jan 19 08:43:00 2006 +0000
@@ -40,7 +40,8 @@
 	SDL_VideoSurface &&						\
 	((SDL_VideoSurface->flags & SDL_FULLSCREEN) == SDL_FULLSCREEN) && \
 	(((SDL_VideoSurface->flags & SDL_OPENGL   ) == SDL_OPENGL    ) || \
-	 (strcmp(this->name, "windib") == 0))				\
+	((strcmp(this->name, "windib") == 0) || \
+	 (strcmp(this->name, "gapi") == 0))) \
 )
 #define DDRAW_FULLSCREEN() 						\
 (									\
--- a/src/video/wincommon/SDL_sysevents.c	Thu Jan 19 08:36:41 2006 +0000
+++ b/src/video/wincommon/SDL_sysevents.c	Thu Jan 19 08:43:00 2006 +0000
@@ -47,6 +47,7 @@
 #endif
 
 #ifdef _WIN32_WCE
+#include "SDL_gapivideo.h"
 #define NO_GETKEYBOARDSTATE
 #define NO_CHANGEDISPLAYSETTINGS
 #endif
@@ -101,6 +102,38 @@
 	}
 }
 
+/* for gapi landscape mode */
+static void GapiTransform(SDL_ScreenOrientation rotate, char hires, Sint16 *x, Sint16 *y) {
+	Sint16 rotatedX;
+	Sint16 rotatedY;
+
+	if (hires) {
+		*x = *x * 2;
+		*y = *y * 2;
+	}
+
+	switch(rotate) {
+		case SDL_ORIENTATION_UP:
+			break;
+		case SDL_ORIENTATION_RIGHT:
+			if (!SDL_VideoSurface)
+				break;
+			rotatedX = SDL_VideoSurface->w - *y;
+			rotatedY = *x;
+			*x = rotatedX;
+			*y = rotatedY;
+			break;
+		case SDL_ORIENTATION_LEFT:
+			if (!SDL_VideoSurface)
+				break;
+			rotatedX = *y;
+			rotatedY = SDL_VideoSurface->h - *x;
+			*x = rotatedX;
+			*y = rotatedY;
+			break;
+	}
+}
+
 #endif
 
 static void SDL_RestoreGameMode(void)
@@ -319,6 +352,10 @@
 						posted = SDL_PrivateMouseMotion(0, 1, x, y);
 					}
 				} else {
+#ifdef _WIN32_WCE
+					if (SDL_VideoSurface)
+						GapiTransform(this->hidden->userOrientation, this->hidden->hiresFix, &x, &y);
+#endif
 					posted = SDL_PrivateMouseMotion(0, 0, x, y);
 				}
 			}
@@ -407,6 +444,10 @@
 				} else {
 					x = (Sint16)LOWORD(lParam);
 					y = (Sint16)HIWORD(lParam);
+#ifdef _WIN32_WCE
+					if (SDL_VideoSurface)
+						GapiTransform(this->hidden->userOrientation, this->hidden->hiresFix, &x, &y);
+#endif
 				}
 				posted = SDL_PrivateMouseButton(
 							state, button, x, y);
--- a/src/video/wincommon/SDL_sysmouse.c	Thu Jan 19 08:36:41 2006 +0000
+++ b/src/video/wincommon/SDL_sysmouse.c	Thu Jan 19 08:43:00 2006 +0000
@@ -251,6 +251,7 @@
 /* Check to see if we need to enter or leave mouse relative mode */
 void WIN_CheckMouseMode(_THIS)
 {
+#ifndef _WIN32_WCE 
         /* If the mouse is hidden and input is grabbed, we use relative mode */
         if ( !(SDL_cursorstate & CURSOR_VISIBLE) &&
              (this->input_grab != SDL_GRAB_OFF) ) {
@@ -258,4 +259,7 @@
         } else {
                 mouse_relative = 0;
         }
+#else
+		mouse_relative =  0; 
+#endif
 }
--- a/src/video/windib/SDL_dibevents.c	Thu Jan 19 08:36:41 2006 +0000
+++ b/src/video/windib/SDL_dibevents.c	Thu Jan 19 08:43:00 2006 +0000
@@ -59,6 +59,31 @@
    and give him a chance to handle some messages. */
 static WNDPROC userWindowProc = NULL;
 
+
+#ifdef _WIN32_WCE
+
+WPARAM rotateKey(WPARAM key,SDL_ScreenOrientation direction) 
+{
+	if (direction != SDL_ORIENTATION_LEFT)
+		return key;
+
+	switch (key) {
+		case 0x26: /* up */
+			return 0x27;
+		case 0x27: /* right */
+			return 0x28;
+		case 0x28: /* down */
+			return 0x25;
+		case 0x25: /* left */
+			return 0x26;
+	}
+
+	return key;
+}
+
+#endif 
+
+
 /* The main Win32 event handler */
 LONG
  DIB_HandleMessage(_THIS, HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
@@ -70,6 +95,15 @@
 		case WM_KEYDOWN: {
 			SDL_keysym keysym;
 
+#ifdef _WIN32_WCE
+			// Drop GAPI artefacts
+			if (wParam == 0x84 || wParam == 0x5B)
+				return 0;
+
+			// Rotate key if necessary
+			if (this->hidden->orientation != SDL_ORIENTATION_UP)
+				wParam = rotateKey(wParam, this->hidden->orientation);	
+#endif 
 			/* Ignore repeated keys */
 			if ( lParam&REPEATED_KEYMASK ) {
 				return(0);
@@ -127,6 +161,16 @@
 		case WM_KEYUP: {
 			SDL_keysym keysym;
 
+#ifdef _WIN32_WCE
+			// Drop GAPI artefacts
+			if (wParam == 0x84 || wParam == 0x5B)
+				return 0;
+
+			// Rotate key if necessary
+			if (this->hidden->orientation != SDL_ORIENTATION_UP)
+				wParam = rotateKey(wParam, this->hidden->orientation);	
+#endif
+
 			switch (wParam) {
 				case VK_CONTROL:
 					if ( lParam&EXTENDED_KEYMASK )
--- a/src/video/windib/SDL_dibvideo.c	Thu Jan 19 08:36:41 2006 +0000
+++ b/src/video/windib/SDL_dibvideo.c	Thu Jan 19 08:43:00 2006 +0000
@@ -768,14 +768,15 @@
 	ReleaseDC(SDL_Window, hdc);
 }
 
+
 int DIB_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
 {
 	RGBQUAD *pal;
 	int i;
-#ifndef _WIN32_WCE
+#if (_WIN32_WCE < 400 )
+	HDC hdc;
+#else
 	HDC hdc, mdc;
-#else
-	HDC hdc;
 #endif
 
 	/* Update the display palette */
@@ -805,7 +806,7 @@
 	}
 
 	/* Set the DIB palette and update the display */
-#ifndef _WIN32_WCE
+#if ( _WIN32_WCE >= 400 )
 	mdc = CreateCompatibleDC(hdc);
 	SelectObject(mdc, screen_bmp);
 	SetDIBColorTable(mdc, firstcolor, ncolors, pal);
@@ -817,6 +818,7 @@
 	return(1);
 }
 
+
 static void DIB_CheckGamma(_THIS)
 {
 #ifndef NO_GAMMA_SUPPORT
--- a/src/video/windib/SDL_dibvideo.h	Thu Jan 19 08:36:41 2006 +0000
+++ b/src/video/windib/SDL_dibvideo.h	Thu Jan 19 08:43:00 2006 +0000
@@ -30,6 +30,15 @@
 
 #include <windows.h>
 
+/* for PDA */
+typedef enum
+{
+	SDL_ORIENTATION_UP,
+	SDL_ORIENTATION_DOWN,
+	SDL_ORIENTATION_LEFT,
+	SDL_ORIENTATION_RIGHT
+} SDL_ScreenOrientation;
+
 /* Private display data */
 struct SDL_PrivateVideoData {
     HBITMAP screen_bmp;
@@ -38,6 +47,10 @@
 #define NUM_MODELISTS	4		/* 8, 16, 24, and 32 bits-per-pixel */
     int SDL_nummodes[NUM_MODELISTS];
     SDL_Rect **SDL_modelist[NUM_MODELISTS];
+
+	SDL_ScreenOrientation orientation;
+	int invert;
+	char hiresFix; // using hires mode without defining hires resource
 };
 /* Old variable names */
 #define screen_bmp		(this->hidden->screen_bmp)