diff src/video/os2fslib/SDL_os2fslib.c @ 1190:173c063d4f55

OS/2 port! This was mostly, if not entirely, written by "Doodle" and "Caetano": doodle@scenergy.dfmk.hu daniel@caetano.eng.br --ryan.
author Ryan C. Gordon <icculus@icculus.org>
date Wed, 23 Nov 2005 07:29:56 +0000
parents
children 3692456e7b0f
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/video/os2fslib/SDL_os2fslib.c	Wed Nov 23 07:29:56 2005 +0000
@@ -0,0 +1,2787 @@
+/*
+    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
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <process.h>
+#include <time.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_os2fslib.h"
+
+static ULONG ulFCFToUse =
+        FCF_TITLEBAR |
+        FCF_SYSMENU |
+        FCF_MINBUTTON |
+        FCF_MAXBUTTON |
+        FCF_NOBYTEALIGN |
+        FCF_SIZEBORDER |
+        FCF_TASKLIST;
+
+static int bMouseCaptured   = 0;
+static int bMouseCapturable = 0;
+static HPOINTER hptrGlobalPointer = NULL;
+static HPOINTER hptrCurrentIcon = NULL;
+static int iWindowSizeX = 320;
+static int iWindowSizeY = 200;
+static int bWindowResized = 0;
+
+#pragma pack(1)
+typedef struct BMPINFO
+{
+   BITMAPINFO;
+   RGB  clr;
+} BMPINFO, *PBMPINFO;
+#pragma pack()
+
+
+// Backdoors:
+DECLSPEC void SDLCALL SDL_OS2FSLIB_SetFCFToUse(ULONG ulFCF)
+{
+  ulFCFToUse = ulFCF;
+}
+
+// Configuration defines:
+
+// We have to report empty alpha mask, otherwise SDL will select
+// alpha blitters, and this will have unwanted results, as we don't
+// support alpha channel in FSLib yet.
+#define REPORT_EMPTY_ALPHA_MASK
+
+// Experimental: Move every FSLib_BitBlt() call into window message
+// processing function.
+// This may fix dirt left on desktop. Or not.
+//#define BITBLT_IN_WINMESSAGEPROC
+
+// Experimental-2: Use WinLockWindowUpdate() in around bitblts!
+// This is not enabled, because it seems to cause more problems
+// than good.
+//#define USE_WINLOCKWINDOWUPDATE_AROUND_BITBLTS
+
+// Use the following to show resized image instead of black stuff
+// even if the surface is resizable.
+//#define RESIZE_EVEN_IF_RESIZABLE
+
+/* The translation table from a VK keysym to a SDL keysym */
+static SDLKey HWScanKeyMap[256];
+static SDL_keysym *TranslateKey(int vkey, int chcode, int scancode, SDL_keysym *keysym, int iPressed);
+static int  iShiftIsPressed;
+
+#ifdef BITBLT_IN_WINMESSAGEPROC
+#define WM_UPDATERECTSREQUEST   WM_USER+50
+#endif
+
+#ifdef USE_WINLOCKWINDOWUPDATE_AROUND_BITBLTS
+#define FSLIB_BITBLT(hwnd, buffer, top, left, width, height) \
+    { \
+      WinLockWindowUpdate(HWND_DESKTOP, HWND_DESKTOP); \
+      FSLib_BitBlt(hwnd, buffer, top, left, width, height); \
+      WinLockWindowUpdate(HWND_DESKTOP, NULL); \
+    }
+#else
+#define FSLIB_BITBLT(hwnd, buffer, top, left, width, height) \
+    FSLib_BitBlt(hwnd, buffer, top, left, width, height);
+#endif
+
+/////////////////////////////////////////////////////////////////////
+//
+// SetAccessableWindowPos
+//
+// Same as WinSetWindowPos(), but takes care for the window to be
+// always on the screen, the titlebar will be accessable everytime.
+//
+/////////////////////////////////////////////////////////////////////
+static BOOL SetAccessableWindowPos(HWND hwnd, HWND hwndInsertBehind,
+				   LONG x, LONG y,
+				   LONG cx, LONG cy,
+                                   ULONG fl)
+{
+  SWP swpDesktop, swp;
+  // Get desktop area
+  WinQueryWindowPos(HWND_DESKTOP, &swpDesktop);
+
+  if ((fl & SWP_MOVE) && (fl & SWP_SIZE))
+  {
+    // If both moving and sizing, then change size and pos now!!
+    if (x+cx>swpDesktop.cx)
+      x = swpDesktop.cx - cx;
+    if (x<0)
+      x = 0;
+    if (y<0)
+      y = 0;
+    if (y+cy>swpDesktop.cy)
+      y = swpDesktop.cy - cy;
+    return WinSetWindowPos(hwnd, hwndInsertBehind, x, y, cx, cy, fl);
+  } else
+  if (fl & SWP_MOVE)
+  {
+    // Just moving
+    WinQueryWindowPos(hwnd, &swp);
+    if (x+swp.cx>swpDesktop.cx)
+      x = swpDesktop.cx - swp.cx;
+    if (x<0)
+      x = 0;
+    if (y<0)
+      y = 0;
+    if (y+swp.cy>swpDesktop.cy)
+      y = swpDesktop.cy - swp.cy;
+    return WinSetWindowPos(hwnd, hwndInsertBehind, x, y, cx, cy, fl);
+  } else
+  if (fl & SWP_SIZE)
+  {
+    // Just sizing
+    WinQueryWindowPos(hwnd, &swp);
+    x = swp.x;
+    y = swp.y;
+    if (x+cx>swpDesktop.cx)
+      x = swpDesktop.cx - cx;
+    if (x<0)
+      x = 0;
+    if (y<0)
+      y = 0;
+    if (y+cy>swpDesktop.cy)
+      y = swpDesktop.cy - cy;
+    return WinSetWindowPos(hwnd, hwndInsertBehind, x, y, cx, cy, fl | SWP_MOVE);
+  } else
+  return WinSetWindowPos(hwnd, hwndInsertBehind, x, y, cx, cy, fl);
+}
+
+/////////////////////////////////////////////////////////////////////
+//
+// TranslateKey
+//
+// This creates SDL Keycodes from VK_ and hardware scan codes
+//
+/////////////////////////////////////////////////////////////////////
+static SDL_keysym *TranslateKey(int vkey, int chcode, int scancode, SDL_keysym *keysym, int iPressed)
+{
+  keysym->scancode = (unsigned char) scancode;
+  keysym->mod = KMOD_NONE;
+  keysym->unicode = 0;
+
+  if (iPressed && SDL_TranslateUNICODE)
+  {
+    // TODO:
+    // Implement real unicode conversion!
+    if (chcode)
+      keysym->unicode = chcode;
+    else
+      keysym->unicode = vkey;
+  }
+
+  keysym->sym = HWScanKeyMap[scancode];
+
+  // Now stuffs based on state of shift key(s)!
+  if (vkey == VK_SHIFT)
+  {
+    iShiftIsPressed = iPressed;
+  }
+
+  if ((iShiftIsPressed) && (SDL_TranslateUNICODE))
+  {
+    // Change syms, if Unicode stuff is required
+    // I think it's silly, but it's SDL...
+    switch (keysym->sym)
+    {
+      case SDLK_BACKQUOTE:
+	keysym->sym = '~';
+	break;
+      case SDLK_1:
+	keysym->sym = SDLK_EXCLAIM;
+	break;
+      case SDLK_2:
+	keysym->sym = SDLK_AT;
+	break;
+      case SDLK_3:
+	keysym->sym = SDLK_HASH;
+	break;
+      case SDLK_4:
+	keysym->sym = SDLK_DOLLAR;
+	break;
+      case SDLK_5:
+	keysym->sym = '%';
+	break;
+      case SDLK_6:
+	keysym->sym = SDLK_CARET;
+	break;
+      case SDLK_7:
+	keysym->sym = SDLK_AMPERSAND;
+	break;
+      case SDLK_8:
+	keysym->sym = SDLK_ASTERISK;
+	break;
+      case SDLK_9:
+	keysym->sym = SDLK_LEFTPAREN;
+	break;
+      case SDLK_0:
+	keysym->sym = SDLK_RIGHTPAREN;
+	break;
+      case SDLK_MINUS:
+	keysym->sym = SDLK_UNDERSCORE;
+	break;
+      case SDLK_PLUS:
+	keysym->sym = SDLK_EQUALS;
+	break;
+
+      case SDLK_LEFTBRACKET:
+	keysym->sym = '{';
+	break;
+      case SDLK_RIGHTBRACKET:
+	keysym->sym = '}';
+	break;
+
+      case SDLK_SEMICOLON:
+	keysym->sym = SDLK_COLON;
+	break;
+      case SDLK_QUOTE:
+	keysym->sym = SDLK_QUOTEDBL;
+	break;
+      case SDLK_BACKSLASH:
+	keysym->sym = '|';
+	break;
+
+      case SDLK_COMMA:
+	keysym->sym = SDLK_LESS;
+	break;
+      case SDLK_PERIOD:
+	keysym->sym = SDLK_GREATER;
+	break;
+      case SDLK_SLASH:
+	keysym->sym = SDLK_QUESTION;
+	break;
+
+      default:
+	break;
+    }
+  }
+  return keysym;
+}
+
+#define CONVERTMOUSEPOSITION()  \
+        /* We have to inverse the mouse position, because every non-os/2 system */                                                \
+        /* has a coordinate system where the (0;0) is the top-left corner,      */                                                \
+	/* while on os/2 it's the bottom left corner!                           */                                                \
+	if (FSLib_QueryFSMode(hwnd))                                                                                              \
+	{                                                                                                                         \
+	  /* We're in FS mode!                                                        */                                          \
+	  /* In FS mode our window is as big as fullscreen mode, but not necessary as */                                          \
+	  /* big as the source buffer (can be bigger)                                 */                                          \
+          /* So, limit mouse pos to source buffer size!                               */                                          \
+	  if (ppts->x<0) ppts->x = 0;                                                                                             \
+	  if (ppts->y<0) ppts->y = 0;                                                                                             \
+	  if (ppts->x>=pVideo->hidden->SrcBufferDesc.uiXResolution) ppts->x = pVideo->hidden->SrcBufferDesc.uiXResolution-1;      \
+          if (ppts->y>=pVideo->hidden->SrcBufferDesc.uiYResolution) ppts->y = pVideo->hidden->SrcBufferDesc.uiYResolution-1;      \
+          pVideo->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account!  */                                   \
+          ptl.x = ppts->x; ptl.y = ppts->y;                                                                                       \
+          WinMapWindowPoints(pVideo->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);                                                  \
+	  WinSetPointerPos(HWND_DESKTOP, ptl.x, ptl.y);                                                                           \
+	  /* Then convert OS/2 position to SDL position */                                                                        \
+          ppts->y = pVideo->hidden->SrcBufferDesc.uiYResolution - ppts->y - 1;                                                    \
+	} else                                                                                                                    \
+	{                                                                                                                         \
+	  SWP swpClient;                                                                                                          \
+          /* We're in windowed mode! */                                                                                           \
+	  WinQueryWindowPos(pVideo->hidden->hwndClient, &swpClient);                                                              \
+          /* Convert OS/2 mouse position to SDL position, and also scale it! */                                                   \
+	  (ppts->x) = (ppts->x) * pVideo->hidden->SrcBufferDesc.uiXResolution / swpClient.cx;                                       \
+	  (ppts->y) = (ppts->y) * pVideo->hidden->SrcBufferDesc.uiYResolution / swpClient.cy;                                       \
+	  (ppts->y) = pVideo->hidden->SrcBufferDesc.uiYResolution - (ppts->y)  - 1;                                                 \
+	}
+
+
+
+/////////////////////////////////////////////////////////////////////
+//
+// WndProc
+//
+// This is the message processing window procedure for the
+// SDLWindowClass, which is the client window in our application.
+// It handles switching back and away from the app (taking care of
+// going out and back to and from fullscreen mode), sending keystrokes
+// and mouse events to where it has to be sent, etc...
+//
+/////////////////////////////////////////////////////////////////////
+static MRESULT EXPENTRY WndProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
+{
+  HPS ps;
+  RECTL rcl;
+  SDL_VideoDevice *pVideo = NULL;
+
+  switch (msg)
+  {
+    case WM_CHAR:  // Keypress notification
+#ifdef DEBUG_BUILD
+//      printf("WM_CHAR\n"); fflush(stdout);
+#endif
+      pVideo = WinQueryWindowPtr(hwnd, 0);
+      if (pVideo)
+      {
+        /*
+        // We skip repeated keys:
+        if (CHARMSG(&msg)->cRepeat>1)
+        {
+#ifdef DEBUG_BUILD
+//          printf("Repeated key (%d), skipping...\n", CHARMSG(&msg)->cRepeat); fflush(stdout);
+#endif
+          return (MRESULT) TRUE;
+        }
+        */
+
+        // If it's not repeated, then let's see if its pressed or released!
+	if (SHORT1FROMMP(mp1) & KC_KEYUP)
+	{
+	  // A key has been released
+          SDL_keysym keysym;
+
+#ifdef DEBUG_BUILD
+//          printf("WM_CHAR, keyup, code is [0x%0x]\n", CHAR4FROMMP(mp1)); // HW scan code
+#endif
+
+          // One problem is with F1, which gets only the keyup message because
+          // it is a system key.
+	  // So, when we get keyup message, we simulate keydown too!
+	  // UPDATE:
+	  //  This problem should be solved now, that the accelerator keys are
+	  //  disabled for this window!
+          /*
+          if (SHORT2FROMMP(mp2)==VK_F1)
+          {
+            SDL_PrivateKeyboard(SDL_PRESSED, TranslateKey(SHORT2FROMMP(mp2), // VK_ code
+                                                           SHORT1FROMMP(mp2), // Character code
+                                                           CHAR4FROMMP(mp1),  // HW Scan code
+                                                           &keysym,0));
+	  }*/
+
+          SDL_PrivateKeyboard(SDL_RELEASED, TranslateKey(SHORT2FROMMP(mp2), // VK_ code
+							 SHORT1FROMMP(mp2), // Character code
+							 CHAR4FROMMP(mp1),  // HW Scan code
+                                                         &keysym,0));
+          
+	} else
+	{
+          // A key has been pressed
+          SDL_keysym keysym;
+
+#ifdef DEBUG_BUILD
+//          printf("WM_CHAR, keydown, code is [0x%0x]\n", CHAR4FROMMP(mp1)); // HW scan code
+#endif
+	  // Check for fastkeys: ALT+HOME to toggle FS mode
+          //                     ALT+END to close app
+	  if ((SHORT1FROMMP(mp1) & KC_ALT) &&
+	      (SHORT2FROMMP(mp2) == VK_HOME))
+	  {
+#ifdef DEBUG_BUILD
+	    printf(" Pressed ALT+HOME!\n"); fflush(stdout);
+#endif
+	    // Only switch between fullscreen and back if it's not
+	    // a resizable mode!
+            if (
+                (!pVideo->hidden->pSDLSurface) ||
+                ((pVideo->hidden->pSDLSurface)
+                 && ((pVideo->hidden->pSDLSurface->flags & SDL_RESIZABLE)==0)
+                )
+               )
+	      FSLib_ToggleFSMode(hwnd, !FSLib_QueryFSMode(hwnd));
+#ifdef DEBUG_BUILD
+            else
+	      printf(" Resizable mode, so discarding ALT+HOME!\n"); fflush(stdout);
+#endif
+	  } else
+	  if ((SHORT1FROMMP(mp1) & KC_ALT) &&
+	      (SHORT2FROMMP(mp2) == VK_END))
+          {
+#ifdef DEBUG_BUILD
+            printf(" Pressed ALT+END!\n"); fflush(stdout);
+#endif
+            // Close window, and get out of loop!
+            // Also send event to SDL application, but we won't
+            // wait for it to be processed!
+            SDL_PrivateQuit();
+            WinPostMsg(hwnd, WM_QUIT, 0, 0);
+	  } else
+          {
+            
+	    SDL_PrivateKeyboard(SDL_PRESSED, TranslateKey(SHORT2FROMMP(mp2), // VK_ code
+							  SHORT1FROMMP(mp2), // Character code
+							  CHAR4FROMMP(mp1),  // HW Scan code
+                                                          &keysym,1));
+            
+	  }
+	}
+      }
+      return (MRESULT) TRUE;
+
+    case WM_TRANSLATEACCEL:
+      {
+	PQMSG pqmsg;
+	pqmsg = (PQMSG) mp1;
+	if (mp1)
+	{
+	  if (pqmsg->msg == WM_CHAR)
+	  {
+	    // WM_CHAR message!
+	    // Let's filter the ALT keypress and all other acceleration keys!
+	    return (MRESULT) FALSE;
+	  }
+	}
+        break; // Default processing (pass to parent until frame control)
+      }
+
+    case WM_PAINT:  // Window redraw!
+#ifdef DEBUG_BUILD
+      printf("WM_PAINT (0x%x)\n", hwnd); fflush(stdout);
+#endif
+      ps = WinBeginPaint(hwnd,0,&rcl);
+      pVideo = FSLib_GetUserParm(hwnd);
+      if (pVideo)
+      {
+        if (!pVideo->hidden->pSDLSurface)
+        {
+          RECTL rclRect;
+          // So, don't blit now!
+#ifdef DEBUG_BUILD
+          printf("WM_PAINT : Skipping blit while resizing (Pre!)!\n"); fflush(stdout);
+#endif
+          WinQueryWindowRect(hwnd, &rclRect);
+          // Fill with black
+          WinFillRect(ps, &rclRect, CLR_BLACK);
+        } else
+        {
+          if (DosRequestMutexSem(pVideo->hidden->hmtxUseSrcBuffer, 1000)==NO_ERROR)
+          {
+            int iTop, iLeft, iWidth, iHeight;
+            int iXScaleError, iYScaleError;
+            int iXScaleError2, iYScaleError2;
+            SWP swp;
+            
+            // Re-blit the modified area!
+            // For this, we have to calculate the points, scaled!
+            WinQueryWindowPos(hwnd, &swp);
+#ifdef DEBUG_BUILD
+            printf("WM_PAINT : WinSize: %d %d, BufSize: %d %d\n",
+                   swp.cx,
+                   swp.cy,
+                   pVideo->hidden->SrcBufferDesc.uiXResolution,
+                   pVideo->hidden->SrcBufferDesc.uiYResolution
+                  );
+            fflush(stdout);
+#endif
+
+#ifndef RESIZE_EVEN_IF_RESIZABLE
+            // But only blit if the window is not resizable, or if
+            // the window is resizable and the source buffer size is the
+            // same as the destination buffer size!
+            if ((!pVideo->hidden->pSDLSurface) ||
+                ((pVideo->hidden->pSDLSurface) &&
+                 (pVideo->hidden->pSDLSurface->flags & SDL_RESIZABLE) &&
+                 ((swp.cx != pVideo->hidden->SrcBufferDesc.uiXResolution) ||
+                  (swp.cy != pVideo->hidden->SrcBufferDesc.uiYResolution)
+                 ) &&
+                 (!FSLib_QueryFSMode(hwnd))
+                )
+               )
+            {
+              RECTL rclRect;
+              // Resizable surface and in resizing!
+              // So, don't blit now!
+#ifdef DEBUG_BUILD
+              printf("WM_PAINT : Skipping blit while resizing!\n"); fflush(stdout);
+#endif
+              WinQueryWindowRect(hwnd, &rclRect);
+              // Fill with black
+              WinFillRect(ps, &rclRect, CLR_BLACK);
+            } else
+#endif
+            {
+  
+              iXScaleError = (pVideo->hidden->SrcBufferDesc.uiXResolution-1) / swp.cx;
+              iYScaleError = (pVideo->hidden->SrcBufferDesc.uiYResolution-1) / swp.cy;
+              if (iXScaleError<0) iXScaleError = 0;
+              if (iYScaleError<0) iYScaleError = 0;
+              iXScaleError2 = (swp.cx-1)/(pVideo->hidden->SrcBufferDesc.uiXResolution);
+              iYScaleError2 = (swp.cy-1)/(pVideo->hidden->SrcBufferDesc.uiYResolution);
+              if (iXScaleError2<0) iXScaleError2 = 0;
+              if (iYScaleError2<0) iYScaleError2 = 0;
+      
+              iTop = (swp.cy - rcl.yTop) * pVideo->hidden->SrcBufferDesc.uiYResolution / swp.cy - iYScaleError;
+              iLeft = rcl.xLeft * pVideo->hidden->SrcBufferDesc.uiXResolution / swp.cx - iXScaleError;
+              iWidth = ((rcl.xRight-rcl.xLeft) * pVideo->hidden->SrcBufferDesc.uiXResolution + swp.cx-1)
+                / swp.cx + 2*iXScaleError;
+              iHeight = ((rcl.yTop-rcl.yBottom) * pVideo->hidden->SrcBufferDesc.uiYResolution + swp.cy-1)
+                / swp.cy + 2*iYScaleError;
+      
+              iWidth+=iXScaleError2;
+              iHeight+=iYScaleError2;
+      
+              if (iTop<0) iTop = 0;
+              if (iLeft<0) iLeft = 0;
+              if (iTop+iHeight>pVideo->hidden->SrcBufferDesc.uiYResolution) iHeight = pVideo->hidden->SrcBufferDesc.uiYResolution-iTop;
+              if (iLeft+iWidth>pVideo->hidden->SrcBufferDesc.uiXResolution) iWidth = pVideo->hidden->SrcBufferDesc.uiXResolution-iLeft;
+    
+#ifdef DEBUG_BUILD
+              printf("WM_PAINT : BitBlt: %d %d -> %d %d (Buf %d x %d)\n",
+                     iTop, iLeft, iWidth, iHeight,
+                     pVideo->hidden->SrcBufferDesc.uiXResolution,
+                     pVideo->hidden->SrcBufferDesc.uiYResolution
+                    );
+              fflush(stdout);
+#endif
+                    
+              FSLIB_BITBLT(hwnd, pVideo->hidden->pchSrcBuffer, iTop, iLeft, iWidth, iHeight);
+            }
+  
+            DosReleaseMutexSem(pVideo->hidden->hmtxUseSrcBuffer);
+          }
+        }
+      }
+#ifdef DEBUG_BUILD
+      else
+      {
+	printf("WM_PAINT : No pVideo!\n"); fflush(stdout);
+      }
+#endif
+      WinEndPaint(ps);
+#ifdef DEBUG_BUILD
+      printf("WM_PAINT : Done.\n");
+      fflush(stdout);
+#endif
+      return 0;
+
+    case WM_SIZE:
+      {
+#ifdef DEBUG_BUILD
+	printf("WM_SIZE : (%d %d)\n",
+	       SHORT1FROMMP(mp2), SHORT2FROMMP(mp2)); fflush(stdout);
+#endif
+        iWindowSizeX = SHORT1FROMMP(mp2);
+        iWindowSizeY = SHORT2FROMMP(mp2);
+        bWindowResized = 1;
+
+	// Make sure the window will be redrawn
+        WinInvalidateRegion(hwnd, NULL, TRUE);
+      }
+      break;
+
+    case WM_FSLIBNOTIFICATION:
+#ifdef DEBUG_BUILD
+        printf("WM_FSLIBNOTIFICATION\n"); fflush(stdout);
+#endif
+      if ((int)mp1 == FSLN_TOGGLEFSMODE)
+      {
+	// FS mode changed, reblit image!
+	pVideo = FSLib_GetUserParm(hwnd);
+	if (pVideo)
+        {
+          if (!pVideo->hidden->pSDLSurface)
+          {
+            // Resizable surface and in resizing!
+            // So, don't blit now!
+#ifdef DEBUG_BUILD
+            printf("WM_FSLIBNOTIFICATION : Can not blit if there is no surface, doing nothing.\n"); fflush(stdout);
+#endif
+          } else
+          {
+            if (DosRequestMutexSem(pVideo->hidden->hmtxUseSrcBuffer, 1000)==NO_ERROR)
+            {
+              if (pVideo->hidden->pSDLSurface)
+              {
+#ifndef RESIZE_EVEN_IF_RESIZABLE
+                SWP swp;
+
+                // But only blit if the window is not resizable, or if
+                // the window is resizable and the source buffer size is the
+                // same as the destination buffer size!
+                WinQueryWindowPos(hwnd, &swp);
+                if ((!pVideo->hidden->pSDLSurface) ||
+                    (
+                     (pVideo->hidden->pSDLSurface) &&
+                     (pVideo->hidden->pSDLSurface->flags & SDL_RESIZABLE) &&
+                     ((swp.cx != pVideo->hidden->SrcBufferDesc.uiXResolution) ||
+                      (swp.cy != pVideo->hidden->SrcBufferDesc.uiYResolution)
+                     ) &&
+                     (!FSLib_QueryFSMode(hwnd))
+                    )
+                   )
+                {
+                  // Resizable surface and in resizing!
+                  // So, don't blit now!
+#ifdef DEBUG_BUILD
+                  printf("WM_FSLIBNOTIFICATION : Cannot blit while resizing, doing nothing.\n"); fflush(stdout);
+#endif
+                } else
+#endif
+                {
+#ifdef DEBUG_BUILD
+                  printf("WM_FSLIBNOTIFICATION : Blitting!\n"); fflush(stdout);
+#endif
+                  FSLIB_BITBLT(hwnd, pVideo->hidden->pchSrcBuffer,
+                               0, 0,
+                               pVideo->hidden->SrcBufferDesc.uiXResolution,
+                               pVideo->hidden->SrcBufferDesc.uiYResolution);
+                }
+              }
+#ifdef DEBUG_BUILD
+              else
+                printf("WM_FSLIBNOTIFICATION : No public surface!\n"); fflush(stdout);
+#endif
+  
+              DosReleaseMutexSem(pVideo->hidden->hmtxUseSrcBuffer);
+            }
+          }
+	}
+      }
+      return (MPARAM) 1;
+
+    case WM_ACTIVATE:
+#ifdef DEBUG_BUILD
+      printf("WM_ACTIVATE\n"); fflush(stdout);
+#endif
+
+      pVideo = FSLib_GetUserParm(hwnd);
+      if (pVideo)
+      {
+        pVideo->hidden->fInFocus = (int) mp1;
+        if (pVideo->hidden->fInFocus)
+        {
+          // Went into focus
+          if ((pVideo->hidden->iMouseVisible) && (!bMouseCaptured))
+            WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE));
+          else
+	    WinSetPointer(HWND_DESKTOP, NULL);
+
+	  if (bMouseCapturable)
+	  {
+            // Re-capture the mouse, if we captured it before!
+	    WinSetCapture(HWND_DESKTOP, hwnd);
+            bMouseCaptured = 1;
+            {
+              SWP swpClient;
+              POINTL ptl;
+              // Center the mouse to the middle of the window!
+              WinQueryWindowPos(pVideo->hidden->hwndClient, &swpClient);
+              ptl.x = 0; ptl.y = 0;
+              WinMapWindowPoints(pVideo->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
+              pVideo->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account!  */
+              WinSetPointerPos(HWND_DESKTOP,
+                               ptl.x + swpClient.cx/2,
+                               ptl.y + swpClient.cy/2);
+            }
+	  }
+        } else
+        {
+          // Went out of focus
+	  WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE));
+
+	  if (bMouseCaptured)
+	  {
+            // Release the mouse
+	    WinSetCapture(HWND_DESKTOP, hwnd);
+            bMouseCaptured = 0;
+	  }
+        }
+      }
+#ifdef DEBUG_BUILD
+      printf("WM_ACTIVATE done\n"); fflush(stdout);
+#endif
+
+      break;
+
+    case WM_BUTTON1DOWN:
+#ifdef DEBUG_BUILD
+      printf("WM_BUTTON1DOWN\n"); fflush(stdout);
+#endif
+
+      pVideo = FSLib_GetUserParm(hwnd);
+      if (pVideo)
+      {
+	SDL_PrivateMouseButton(SDL_PRESSED,
+                               SDL_BUTTON_LEFT,
+                               0, 0); // Don't report mouse movement!
+
+	if (bMouseCapturable)
+	{
+	  // We should capture the mouse!
+	  if (!bMouseCaptured)
+	  {
+	    WinSetCapture(HWND_DESKTOP, hwnd);
+            WinSetPointer(HWND_DESKTOP, NULL);
+            bMouseCaptured = 1;
+            {
+              SWP swpClient;
+              POINTL ptl;
+              // Center the mouse to the middle of the window!
+              WinQueryWindowPos(pVideo->hidden->hwndClient, &swpClient);
+              ptl.x = 0; ptl.y = 0;
+              WinMapWindowPoints(pVideo->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
+              pVideo->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account!  */
+              WinSetPointerPos(HWND_DESKTOP,
+                               ptl.x + swpClient.cx/2,
+                               ptl.y + swpClient.cy/2);
+            }
+	  }
+	}
+      }
+      break;
+    case WM_BUTTON1UP:
+#ifdef DEBUG_BUILD
+      printf("WM_BUTTON1UP\n"); fflush(stdout);
+#endif
+      SDL_PrivateMouseButton(SDL_RELEASED,
+                             SDL_BUTTON_LEFT,
+                             0, 0); // Don't report mouse movement!
+      break;
+    case WM_BUTTON2DOWN:
+#ifdef DEBUG_BUILD
+      printf("WM_BUTTON2DOWN\n"); fflush(stdout);
+#endif
+
+      pVideo = FSLib_GetUserParm(hwnd);
+      if (pVideo)
+      {
+	SDL_PrivateMouseButton(SDL_PRESSED,
+                               SDL_BUTTON_RIGHT,
+                               0, 0); // Don't report mouse movement!
+
+	if (bMouseCapturable)
+	{
+	  // We should capture the mouse!
+	  if (!bMouseCaptured)
+	  {
+	    WinSetCapture(HWND_DESKTOP, hwnd);
+            WinSetPointer(HWND_DESKTOP, NULL);
+            bMouseCaptured = 1;
+            {
+              SWP swpClient;
+              POINTL ptl;
+              // Center the mouse to the middle of the window!
+              WinQueryWindowPos(pVideo->hidden->hwndClient, &swpClient);
+              ptl.x = 0; ptl.y = 0;
+              WinMapWindowPoints(pVideo->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
+              pVideo->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account!  */
+              WinSetPointerPos(HWND_DESKTOP,
+                               ptl.x + swpClient.cx/2,
+                               ptl.y + swpClient.cy/2);
+            }
+	  }
+	}
+
+      }
+      break;
+    case WM_BUTTON2UP:
+#ifdef DEBUG_BUILD
+      printf("WM_BUTTON2UP\n"); fflush(stdout);
+#endif
+      SDL_PrivateMouseButton(SDL_RELEASED,
+                             SDL_BUTTON_RIGHT,
+                             0, 0); // Don't report mouse movement!
+      break;
+    case WM_BUTTON3DOWN:
+#ifdef DEBUG_BUILD
+      printf("WM_BUTTON3DOWN\n"); fflush(stdout);
+#endif
+
+      pVideo = FSLib_GetUserParm(hwnd);
+      if (pVideo)
+      {
+        SDL_PrivateMouseButton(SDL_PRESSED,
+                               SDL_BUTTON_MIDDLE,
+                               0, 0); // Don't report mouse movement!
+        
+	if (bMouseCapturable)
+	{
+	  // We should capture the mouse!
+	  if (!bMouseCaptured)
+	  {
+	    WinSetCapture(HWND_DESKTOP, hwnd);
+            WinSetPointer(HWND_DESKTOP, NULL);
+            bMouseCaptured = 1;
+            {
+              SWP swpClient;
+              POINTL ptl;
+              // Center the mouse to the middle of the window!
+              WinQueryWindowPos(pVideo->hidden->hwndClient, &swpClient);
+              ptl.x = 0; ptl.y = 0;
+              WinMapWindowPoints(pVideo->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
+              pVideo->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account!  */
+              WinSetPointerPos(HWND_DESKTOP,
+                               ptl.x + swpClient.cx/2,
+                               ptl.y + swpClient.cy/2);
+            }
+	  }
+	}
+      }
+      break;
+    case WM_BUTTON3UP:
+#ifdef DEBUG_BUILD
+      printf("WM_BUTTON3UP\n"); fflush(stdout);
+#endif
+      SDL_PrivateMouseButton(SDL_RELEASED,
+                             SDL_BUTTON_MIDDLE,
+                             0, 0); // Don't report mouse movement!
+      break;
+    case WM_MOUSEMOVE:
+#ifdef DEBUG_BUILD
+//      printf("WM_MOUSEMOVE\n"); fflush(stdout);
+#endif
+
+      pVideo = FSLib_GetUserParm(hwnd);
+      if (pVideo)
+      {
+        if (pVideo->hidden->iSkipWMMOUSEMOVE)
+        {
+          pVideo->hidden->iSkipWMMOUSEMOVE--;
+        } else
+        {
+          POINTS *ppts = (POINTS *) (&mp1);
+          POINTL ptl;
+
+          CONVERTMOUSEPOSITION();
+
+          if (bMouseCaptured)
+          {
+            SWP swpClient;
+            // Send relative mouse position, and re-center the mouse
+            // Reposition the mouse to the center of the screen/window
+            SDL_PrivateMouseMotion(0, // Buttons not changed
+                                   1, // Relative position
+                                   ppts->x - (pVideo->hidden->SrcBufferDesc.uiXResolution/2),
+                                   ppts->y+1 - (pVideo->hidden->SrcBufferDesc.uiYResolution/2));
+
+            WinQueryWindowPos(pVideo->hidden->hwndClient, &swpClient);
+            ptl.x = 0; ptl.y = 0;
+            WinMapWindowPoints(pVideo->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
+            pVideo->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account!  */
+            // Center the mouse to the middle of the window!
+            WinSetPointerPos(HWND_DESKTOP,
+                             ptl.x + swpClient.cx/2,
+                             ptl.y + swpClient.cy/2);
+          } else
+          {
+            // Send absolute mouse position
+            SDL_PrivateMouseMotion(0, // Buttons not changed
+                                   0, // Absolute position
+                                   ppts->x,
+                                   ppts->y);
+          }
+        }
+        if ((pVideo->hidden->iMouseVisible) && (!bMouseCaptured))
+        {
+#ifdef DEBUG_BUILD
+//          printf("WM_MOUSEMOVE : ptr = %p\n", hptrGlobalPointer); fflush(stdout);
+#endif
+
+          if (hptrGlobalPointer)
+            WinSetPointer(HWND_DESKTOP, hptrGlobalPointer);
+          else
+            WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE));
+        }
+        else
+        {
+          WinSetPointer(HWND_DESKTOP, NULL);
+        }
+      }
+#ifdef DEBUG_BUILD
+//      printf("WM_MOUSEMOVE done\n"); fflush(stdout);
+#endif
+
+      return (MRESULT) FALSE;
+    case WM_CLOSE: // Window close
+#ifdef DEBUG_BUILD
+      printf("WM_CLOSE\n"); fflush(stdout);
+#endif
+
+      pVideo = FSLib_GetUserParm(hwnd);
+      if (pVideo)
+      {
+        // Send Quit message to the SDL application!
+        SDL_PrivateQuit();
+        return 0;
+      }
+      break;
+
+#ifdef BITBLT_IN_WINMESSAGEPROC
+    case WM_UPDATERECTSREQUEST:
+      pVideo = FSLib_GetUserParm(hwnd);
+      if ((pVideo) && (pVideo->hidden->pSDLSurface))
+      {
+        if (DosRequestMutexSem(pVideo->hidden->hmtxUseSrcBuffer, SEM_INDEFINITE_WAIT)==NO_ERROR)
+        {
+          int numrects;
+          SDL_Rect *rects;
+          int i;
+          SWP swp;
+
+          numrects = (int) mp1;
+          rects = (SDL_Rect *) mp2;
+
+          WinQueryWindowPos(hwnd, &swp);
+#ifndef RESIZE_EVEN_IF_RESIZABLE
+          if ((!pVideo->hidden->pSDLSurface) ||
+              (
+               (pVideo->hidden->pSDLSurface) &&
+               (pVideo->hidden->pSDLSurface->flags & SDL_RESIZABLE) &&
+               ((swp.cx != pVideo->hidden->SrcBufferDesc.uiXResolution) ||
+                (swp.cy != pVideo->hidden->SrcBufferDesc.uiYResolution)
+               ) &&
+               (!FSLib_QueryFSMode(hwnd))
+              )
+             )
+          {
+            // Resizable surface and in resizing!
+            // So, don't blit now!
+#ifdef DEBUG_BUILD
+            printf("[WM_UPDATERECTSREQUEST] : Skipping blit while resizing!\n"); fflush(stdout);
+#endif
+          } else
+#endif
+          {
+#ifdef DEBUG_BUILD
+            printf("[WM_UPDATERECTSREQUEST] : Blitting!\n"); fflush(stdout);
+#endif
+          
+            // Blit the changed areas
+            for (i=0; i<numrects; i++)
+              FSLIB_BITBLT(hwnd, pVideo->hidden->pchSrcBuffer,
+                           rects[i].y, rects[i].x, rects[i].w, rects[i].h);
+          }
+          DosReleaseMutexSem(pVideo->hidden->hmtxUseSrcBuffer);
+        }
+      }
+      return 0;
+#endif
+
+    default:
+#ifdef DEBUG_BUILD
+      printf("Unhandled: %x\n", msg); fflush(stdout);
+#endif
+
+      break;
+  }
+  // Run the default window procedure for unhandled stuffs
+  return WinDefWindowProc(hwnd, msg, mp1, mp2);
+}
+
+/////////////////////////////////////////////////////////////////////
+//
+// PMThreadFunc
+//
+// This function implements the PM-Thread, which initializes the
+// application window itself, the DIVE, and start message processing.
+//
+/////////////////////////////////////////////////////////////////////
+int iNumOfPMThreadInstances = 0; // Global!
+static void PMThreadFunc(void *pParm)
+{
+  SDL_VideoDevice *pVideo = pParm;
+  HAB hab;
+  HMQ hmq;
+  QMSG msg;
+  ULONG fcf;
+
+#ifdef DEBUG_BUILD
+  printf("[PMThreadFunc] : Starting\n"); fflush(stdout);
+#endif
+
+  iNumOfPMThreadInstances++;
+
+  // Initialize PM, create a message queue.
+
+  hab=WinInitialize(0);
+  hmq=WinCreateMsgQueue(hab,0);
+  if (hmq==0)
+  {
+#ifdef DEBUG_BUILD
+    printf("[PMThreadFunc] : Could not create message queue!\n");
+    printf("                 It might be that the application using SDL is not a PM app!\n");
+    fflush(stdout);
+#endif
+    pVideo->hidden->iPMThreadStatus = 2;
+  } else
+  {
+    int rc;
+    RECTL rectl;
+
+    fcf = ulFCFToUse; // Get from global setting
+
+#ifdef DEBUG_BUILD
+    printf("[PMThreadFunc] : FSLib_CreateWindow()!\n");
+    fflush(stdout);
+#endif
+
+    rc = FSLib_CreateWindow(HWND_DESKTOP, 0, &fcf,
+                            "SDL Application",
+                            NULLHANDLE, 0,
+                            &(pVideo->hidden->SrcBufferDesc),
+                            WndProc,
+                            &(pVideo->hidden->hwndClient),
+			    &(pVideo->hidden->hwndFrame));
+
+#ifdef DEBUG_BUILD
+    printf("[PMThreadFunc] : FSLib_CreateWindow() rc = %d\n", rc);
+    fflush(stdout);
+#endif
+
+    if (!rc)
+    {
+#ifdef DEBUG_BUILD
+      printf("[PMThreadFunc] : Could not create FSLib window!\n");
+      fflush(stdout);
+#endif
+      pVideo->hidden->iPMThreadStatus = 3;
+    } else
+    {
+#ifdef DEBUG_BUILD
+      printf("[PMThreadFunc] : FSLib_AddUserParm()!\n");
+      fflush(stdout);
+#endif
+
+      // Store pVideo pointer in window data for client window, so
+      // it will know the instance to which it belongs to.
+      FSLib_AddUserParm(pVideo->hidden->hwndClient, pVideo);
+
+      // Now set default image width height and fourcc!
+#ifdef DEBUG_BUILD
+      printf("[PMThreadFunc] : SetWindowPos()!\n");
+      fflush(stdout);
+#endif
+
+      // Set the position and size of the main window,
+      // and make it visible!
+      // Calculate frame window size from client window size
+      rectl.xLeft = 0;
+      rectl.yBottom = 0;
+      rectl.xRight = pVideo->hidden->SrcBufferDesc.uiXResolution; // Noninclusive
+      rectl.yTop = pVideo->hidden->SrcBufferDesc.uiYResolution; // Noninclusive
+      WinCalcFrameRect(pVideo->hidden->hwndFrame, &rectl, FALSE);
+
+      SetAccessableWindowPos(pVideo->hidden->hwndFrame,
+                             HWND_TOP,
+                             (WinQuerySysValue (HWND_DESKTOP, SV_CXSCREEN) - (rectl.xRight-rectl.xLeft)) / 2,
+                             (WinQuerySysValue (HWND_DESKTOP, SV_CYSCREEN) - (rectl.yTop-rectl.yBottom)) / 2,
+                             (rectl.xRight-rectl.xLeft),
+                             (rectl.yTop-rectl.yBottom),
+                             SWP_SIZE | SWP_ACTIVATE | SWP_SHOW | SWP_MOVE);
+
+#ifdef DEBUG_BUILD
+      printf("[PMThreadFunc] : Entering message loop\n"); fflush(stdout);
+#endif
+      pVideo->hidden->iPMThreadStatus = 1;
+  
+      while (WinGetMsg(hab, (PQMSG)&msg, 0, 0, 0))
+        WinDispatchMsg(hab, (PQMSG) &msg);
+
+#ifdef DEBUG_BUILD
+      printf("[PMThreadFunc] : Leaving message loop\n"); fflush(stdout);
+#endif
+      // We should release the captured the mouse!
+      if (bMouseCaptured)
+      {
+        WinSetCapture(HWND_DESKTOP, NULLHANDLE);
+        bMouseCaptured = 0;
+      }
+      // Destroy our window
+      WinDestroyWindow(pVideo->hidden->hwndFrame); pVideo->hidden->hwndFrame=NULL;
+      // Show pointer to make sure it will not be left hidden.
+      WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE));
+      WinShowPointer(HWND_DESKTOP, TRUE);
+    }
+    // Uninitialize PM
+    WinDestroyMsgQueue(hmq);
+    // All done!
+    pVideo->hidden->iPMThreadStatus = 0;
+  }
+  WinTerminate(hab);
+  /* Commented out, should not be needed anymore, because we send it
+     from WM_CLOSE.
+  // Notify SDL that it should really die now...
+  SDL_PrivateQuit(); SDL_PrivateQuit(); SDL_PrivateQuit(); //... :))
+  */
+#ifdef DEBUG_BUILD
+  printf("[PMThreadFunc] : End, status is %d!\n", pVideo->hidden->iPMThreadStatus); fflush(stdout);
+#endif
+
+  iNumOfPMThreadInstances--;
+
+  // HACK to prevent zombie and hanging SDL applications, which does not take
+  // care of closing the window for some reason:
+  // There are some apps which do not process messages, so do a lot of things
+  // without noticing that the application should close. To close these,
+  // I've thought about the following:
+  // If the window is closed (the execution came here), I wait a bit to
+  // give time to the app to finish its execution. If it does not, I kill it
+  // using DosExit(). Brute force, but should work.
+  if (pVideo->hidden->iPMThreadStatus==0)
+  {
+    DosSleep(5000); // Wait 5 secs
+    // If a new PM thread has been spawned (reinitializing video mode), then all right.
+    // Otherwise, we have a problem, the app doesn't want to stop. Kill!
+    if (iNumOfPMThreadInstances==0)
+    {
+#ifdef DEBUG_BUILD
+      printf("[PMThreadFunc] : It seems that the application haven't terminated itself\n"); fflush(stdout);
+      printf("[PMThreadFunc] : in the last 5 seconds, so we go berserk.\n"); fflush(stdout);
+      printf("[PMThreadFunc] : Brute force mode. :) Killing process! Dieeeee...\n"); fflush(stdout);
+#endif
+      DosExit(EXIT_PROCESS, -1);
+    }
+  }
+  _endthread();
+}
+
+struct WMcursor
+{
+  HBITMAP hbm;
+  HPOINTER hptr;
+  char *pchData;
+};
+
+/* Free a window manager cursor */
+void os2fslib_FreeWMCursor(_THIS, WMcursor *cursor)
+{
+  if (cursor)
+  {
+    GpiDeleteBitmap(cursor->hbm);
+    WinDestroyPointer(cursor->hptr);
+    free(cursor->pchData);
+    free(cursor);
+  }
+}
+
+/* Local functions to convert the SDL cursor mask into OS/2 format */
+static void memnot(Uint8 *dst, Uint8 *src, int len)
+{
+  while ( len-- > 0 )
+    *dst++ = ~*src++;
+}
+static void memxor(Uint8 *dst, Uint8 *src1, Uint8 *src2, int len)
+{
+  while ( len-- > 0 )
+    *dst++ = (*src1++)^(*src2++);
+}
+
+/* Create a black/white window manager cursor */
+WMcursor *os2fslib_CreateWMCursor_Win(_THIS, Uint8 *data, Uint8 *mask,
+                                      int w, int h, int hot_x, int hot_y)
+{
+  HPOINTER hptr;
+  HBITMAP hbm;
+  BITMAPINFOHEADER bmih;
+  BMPINFO          bmi;
+  HPS              hps;
+  char *pchTemp;
+  char *xptr, *aptr;
+  int maxx, maxy;
+  int i, run, pad;
+  WMcursor *pResult;
+
+  maxx = WinQuerySysValue(HWND_DESKTOP, SV_CXPOINTER);
+  maxy = WinQuerySysValue(HWND_DESKTOP, SV_CYPOINTER);
+
+  // Check for max size!
+  if ((w>maxx) || (h>maxy))
+    return (WMcursor *) NULL;
+
+  pResult = (WMcursor *) malloc(sizeof(WMcursor));
+  if (!pResult) return (WMcursor *) NULL;
+
+  pchTemp = (char *) malloc((maxx + 7)/8 * maxy*2);
+  if (!pchTemp)
+  {
+    free(pResult);
+    return (WMcursor *) NULL;
+  }
+
+  memset(pchTemp, 0, (maxx + 7)/8 * maxy*2);
+
+  hps = WinGetPS(_this->hidden->hwndClient);
+
+  bmi.cbFix = sizeof(BITMAPINFOHEADER);
+  bmi.cx = maxx;
+  bmi.cy = 2*maxy;
+  bmi.cPlanes = 1;
+  bmi.cBitCount = 1;
+  bmi.argbColor[0].bBlue = 0x00;
+  bmi.argbColor[0].bGreen = 0x00;
+  bmi.argbColor[0].bRed = 0x00;
+  bmi.argbColor[1].bBlue = 0x00;
+  bmi.argbColor[1].bGreen = 0x00;
+  bmi.argbColor[1].bRed = 0xff;
+
+  memset(&bmih, 0, sizeof(BITMAPINFOHEADER));
+  bmih.cbFix = sizeof(BITMAPINFOHEADER);
+  bmih.cx = maxx;
+  bmih.cy = 2*maxy;
+  bmih.cPlanes = 1;
+  bmih.cBitCount = 1;
+
+  run = (w+7)/8;
+  pad = (maxx+7)/8 - run;
+
+  for (i=0; i<h; i++)
+  {
+    xptr = pchTemp + (maxx+7)/8 * (maxy-1-i);
+    aptr = pchTemp + (maxx+7)/8 * (maxy+maxy-1-i);
+    memxor(xptr, data, mask, run);
+    xptr += run;
+    data += run;
+    memnot(aptr, mask, run);
+    mask += run;
+    aptr += run;
+    memset(xptr,  0, pad);
+    xptr += pad;
+    memset(aptr, ~0, pad);
+    aptr += pad;
+  }
+  pad += run;
+  for (i=h ; i<maxy; i++ )
+  {
+    xptr = pchTemp + (maxx+7)/8 * (maxy-1-i);
+    aptr = pchTemp + (maxx+7)/8 * (maxy+maxy-1-i);
+
+    memset(xptr,  0, (maxx+7)/8);
+    xptr += (maxx+7)/8;
+    memset(aptr, ~0, (maxx+7)/8);
+    aptr += (maxx+7)/8;
+  }
+
+  hbm = GpiCreateBitmap(hps, (PBITMAPINFOHEADER2)&bmih, CBM_INIT, (PBYTE) pchTemp, (PBITMAPINFO2)&bmi);
+  hptr = WinCreatePointer(HWND_DESKTOP, hbm, TRUE, hot_x, maxy - hot_y - 1);
+
+#ifdef DEBUG_BUILD
+  printf("HotSpot          : %d ; %d\n", hot_x, hot_y);
+  printf("HPS returned     : %x\n", (ULONG)hps);
+  printf("HBITMAP returned : %x\n", (ULONG)hbm);
+  printf("HPOINTER returned: %x\n", (ULONG)hptr);
+#endif
+
+  WinReleasePS(hps);
+
+#ifdef DEBUG_BUILD
+  printf("[CreateWMCursor] : ptr = %p\n", hptr); fflush(stdout);
+#endif
+
+  pResult->hptr = hptr;
+  pResult->hbm = hbm;
+  pResult->pchData = pchTemp;
+
+#ifdef DEBUG_BUILD
+  printf("[CreateWMCursor] : ptr = %p return.\n", hptr); fflush(stdout);
+#endif
+
+  return (WMcursor *) pResult;
+}
+
+WMcursor *os2fslib_CreateWMCursor_FS(_THIS, Uint8 *data, Uint8 *mask,
+                                     int w, int h, int hot_x, int hot_y)
+{
+#ifdef DEBUG_BUILD
+  printf("[CreateWMCursor_FS] : returning pointer NULL\n"); fflush(stdout);
+#endif
+
+  // In FS mode we'll use software cursor
+  return (WMcursor *) NULL;
+}
+
+/* Show the specified cursor, or hide if cursor is NULL */
+int os2fslib_ShowWMCursor(_THIS, WMcursor *cursor)
+{
+#ifdef DEBUG_BUILD
+  printf("[ShowWMCursor] : ptr = %p\n", cursor); fflush(stdout);
+#endif
+
+  if (cursor)
+  {
+    WinSetPointer(HWND_DESKTOP, cursor->hptr);
+    hptrGlobalPointer = cursor->hptr;
+    _this->hidden->iMouseVisible = 1;
+  }
+  else
+  {
+    WinSetPointer(HWND_DESKTOP, FALSE);
+    hptrGlobalPointer = NULL;
+    _this->hidden->iMouseVisible = 0;
+  }
+
+#ifdef DEBUG_BUILD
+  printf("[ShowWMCursor] : ptr = %p, DONE\n", cursor); fflush(stdout);
+#endif
+
+  return 1;
+}
+
+/* Warp the window manager cursor to (x,y)
+ If NULL, a mouse motion event is posted internally.
+ */
+void os2fslib_WarpWMCursor(_THIS, Uint16 x, Uint16 y)
+{
+  LONG lx, ly;
+  SWP swpClient;
+  POINTL ptlPoints;
+  WinQueryWindowPos(_this->hidden->hwndClient, &swpClient);
+  ptlPoints.x = swpClient.x;
+  ptlPoints.y = swpClient.y;
+  WinMapWindowPoints(_this->hidden->hwndFrame, HWND_DESKTOP, &ptlPoints, 1);
+  lx = ptlPoints.x + (x*swpClient.cx) / _this->hidden->SrcBufferDesc.uiXResolution;
+  ly = ptlPoints.y + swpClient.cy - ((y*swpClient.cy) / _this->hidden->SrcBufferDesc.uiYResolution) - 1;
+
+  SDL_PrivateMouseMotion(0, // Buttons not changed
+                         0, // Absolute position
+                         x,
+                         y);
+
+  WinSetPointerPos(HWND_DESKTOP, lx, ly);
+
+}
+
+/* If not NULL, this is called when a mouse motion event occurs */
+void os2fslib_MoveWMCursor(_THIS, int x, int y)
+{
+  /*
+  SDL_Rect rect;
+
+#ifdef DEBUG_BUILD
+  printf("[MoveWMCursor] : at %d ; %d\n", x, y); fflush(stdout);
+#endif
+
+  rect.x = x;
+  rect.y = y;
+  rect.w = 32;
+  rect.h = 32;
+  os2fslib_UpdateRects(_this, 1, &rect);
+  // TODO!
+  */
+}
+
+/* Determine whether the mouse should be in relative mode or not.
+ This function is called when the input grab state or cursor
+ visibility state changes.
+ If the cursor is not visible, and the input is grabbed, the
+ driver can place the mouse in relative mode, which may result
+ in higher accuracy sampling of the pointer motion.
+ */
+void os2fslib_CheckMouseMode(_THIS)
+{
+}
+
+static void os2fslib_PumpEvents(_THIS)
+{
+  // Notify SDL that if window has been resized!
+  if (
+      (_this->hidden->pSDLSurface) &&
+      (_this->hidden->pSDLSurface->flags & SDL_RESIZABLE) &&
+      (
+       (_this->hidden->SrcBufferDesc.uiXResolution!=iWindowSizeX) ||
+       (_this->hidden->SrcBufferDesc.uiYResolution!=iWindowSizeY)
+      ) &&
+      (iWindowSizeX>0) &&
+      (iWindowSizeY>0)
+     )
+  {
+    static time_t prev_time;
+    time_t curr_time;
+
+    curr_time = time(NULL);
+    if ((difftime(curr_time, prev_time)>=0.25) ||
+        (bWindowResized))
+    {
+      // Make sure we won't flood the event queue with resize events,
+      // only send them at 250 msecs!
+      // (or when the window is resized)
+#ifdef DEBUG_BUILD
+      printf("[os2fslib_PumpEvents] : Calling PrivateResize (%d %d).\n",
+             iWindowSizeX, iWindowSizeY);
+      fflush(stdout);
+#endif
+      // Tell SDL the new size
+      SDL_PrivateResize(iWindowSizeX, iWindowSizeY);
+      prev_time = curr_time;
+      bWindowResized = 0;
+    }
+  }
+}
+
+/* We don't actually allow hardware surfaces other than the main one */
+static int os2fslib_AllocHWSurface(_THIS, SDL_Surface *surface)
+{
+  return(-1);
+}
+static void os2fslib_FreeHWSurface(_THIS, SDL_Surface *surface)
+{
+  return;
+}
+
+/* We need to wait for vertical retrace on page flipped displays */
+static int os2fslib_LockHWSurface(_THIS, SDL_Surface *surface)
+{
+  return(0);
+}
+
+static void os2fslib_UnlockHWSurface(_THIS, SDL_Surface *surface)
+{
+  return;
+}
+
+static int os2fslib_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
+{
+  printf("[os2fslib_SetColors] : TODO!\n"); fflush(stdout);
+  // TODO: Implement paletted modes
+  return(1);
+}
+
+static void os2fslib_DestroyIcon(HWND hwndFrame)
+{
+  if (hptrCurrentIcon)
+  {
+    WinDestroyPointer(hptrCurrentIcon);
+    hptrCurrentIcon = NULL;
+
+    WinSendMsg(hwndFrame,
+               WM_SETICON,
+               NULL,
+               NULL);
+  }
+
+}
+
+/* Set the window icon image */
+void os2fslib_SetIcon(_THIS, SDL_Surface *icon, Uint8 *mask)
+{
+  HWND hwndFrame;
+  SDL_Surface *icon_rgb;
+  HPOINTER hptrIcon;
+  HBITMAP hbm;
+  BITMAPINFOHEADER bmih;
+  BMPINFO          bmi;
+  HPS              hps;
+  char *pchTemp;
+  char *pptr, *mptr, *dptr, *dmptr;
+  int maxx, maxy, w, h, x, y;
+  SDL_Rect bounds;
+
+#ifdef DEBUG_BUILD
+  printf("[os2fslib_SetIcon] : Creating and setting new icon\n"); fflush(stdout);
+#endif
+
+  hwndFrame = WinQueryWindow(_this->hidden->hwndClient, QW_PARENT);
+
+  // Make sure the old icon resource will be free'd!
+  os2fslib_DestroyIcon(hwndFrame);
+
+  if ((!icon) || (!mask))
+    return;
+
+  w = icon->w;
+  h = icon->h;
+
+  maxx = WinQuerySysValue(HWND_DESKTOP, SV_CXICON);
+  maxy = WinQuerySysValue(HWND_DESKTOP, SV_CYICON);
+
+  // Check for max size!
+  if ((w>maxx) || (h>maxy))
+    return;
+
+  pchTemp = (char *) malloc(w * h*2 * 4);
+  if (!pchTemp)
+    return;
+
+  memset(pchTemp, 0, w * h*2 * 4);
+
+  // Convert surface to RGB, if it's not RGB yet!
+  icon_rgb = SDL_CreateRGBSurface(SDL_SWSURFACE, icon->w, icon->h,
+                                  32, 0, 0, 0, 0);
+  if ( icon_rgb == NULL )
+  {
+    free(pchTemp);
+    return;
+  }
+  bounds.x = 0;
+  bounds.y = 0;
+  bounds.w = icon->w;
+  bounds.h = icon->h;
+  if ( SDL_LowerBlit(icon, &bounds, icon_rgb, &bounds) < 0 )
+  {
+    SDL_FreeSurface(icon_rgb);
+    free(pchTemp);
+    return;
+  }
+
+  /* Copy pixels upside-down from RGB surface into BMP, masked with the icon mask */
+
+  // Pixels
+  pptr = (char *) (icon_rgb->pixels);
+  // Mask
+  mptr = mask;
+
+  for (y=0; y<h; y++)
+  {
+    unsigned char uchMaskByte;
+
+    // Destination
+    dptr = pchTemp + w*4 * (h-y-1);
+    // Destination mask
+    dmptr = pchTemp + w*h*4 + w*4 * (h-y-1);
+
+    for (x=0; x<w; x++)
+    {
+      if (x%8==0)
+      {
+        uchMaskByte = (unsigned char) (*mptr);
+        mptr++;
+      } else
+        uchMaskByte <<= 1;
+
+      if (uchMaskByte & 0x80)
+      {
+        // Copy RGB
+        *dptr++ = *pptr++;
+        *dptr++ = *pptr++;
+        *dptr++ = *pptr++;
+        *dptr++ = *pptr++;
+
+        *dmptr++ = 0;
+        *dmptr++ = 0;
+        *dmptr++ = 0;
+        *dmptr++ = 0;
+      } else
+      {
+        // Set pixels to fully transparent
+        *dptr++ = 0; pptr++;
+        *dptr++ = 0; pptr++;
+        *dptr++ = 0; pptr++;
+        *dptr++ = 0; pptr++;
+
+        *dmptr++ = 255;
+        *dmptr++ = 255;
+        *dmptr++ = 255;
+        *dmptr++ = 255;
+      }
+    }
+  }
+
+  // There is no more need for the RGB surface
+  SDL_FreeSurface(icon_rgb);
+
+  hps = WinGetPS(_this->hidden->hwndClient);
+
+  bmi.cbFix = sizeof(BITMAPINFOHEADER);
+  bmi.cx = w;
+  bmi.cy = 2*h;
+  bmi.cPlanes = 1;
+  bmi.cBitCount = 32;
+
+  memset(&bmih, 0, sizeof(BITMAPINFOHEADER));
+  bmih.cbFix = sizeof(BITMAPINFOHEADER);
+  bmih.cx = w;
+  bmih.cy = 2*h;
+  bmih.cPlanes = 1;
+  bmih.cBitCount = 32;
+
+  hbm = GpiCreateBitmap(hps, (PBITMAPINFOHEADER2)&bmih, CBM_INIT, (PBYTE) pchTemp, (PBITMAPINFO2)&bmi);
+  hptrIcon = WinCreatePointer(HWND_DESKTOP, hbm, FALSE, 0, 0);
+
+  WinReleasePS(hps);
+
+  // Free pixel array
+  free(pchTemp);
+
+  // Change icon in frame window
+  WinSendMsg(hwndFrame,
+             WM_SETICON,
+             (MPARAM) hptrIcon,
+             NULL);
+
+  /*
+  // Change icon in switchlist
+  // Seems like it's not needed, the WM_SETICON already does it.
+  {
+    PID pidFrame;
+    HSWITCH hswitchFrame;
+    SWCNTRL swctl;
+
+    WinQueryWindowProcess(hwndFrame, &pidFrame, NULL);
+    hswitchFrame = WinQuerySwitchHandle(hwndFrame, pidFrame);
+    WinQuerySwitchEntry(hswitchFrame, &swctl);
+
+    swctl.hwndIcon = hptrIcon;
+
+    WinChangeSwitchEntry(hswitchFrame, &swctl);
+  }
+  */
+
+  // Store icon handle in global variable
+  hptrCurrentIcon = hptrIcon;
+}
+
+// ------------------------ REAL FUNCTIONS -----------------
+
+
+static void os2fslib_SetCursorManagementFunctions(_THIS, int iForWindowedMode)
+{
+  if (iForWindowedMode)
+  {
+    _this->FreeWMCursor = os2fslib_FreeWMCursor;
+    _this->CreateWMCursor = os2fslib_CreateWMCursor_Win;
+    _this->ShowWMCursor = os2fslib_ShowWMCursor;
+    _this->WarpWMCursor = os2fslib_WarpWMCursor;
+    _this->MoveWMCursor = os2fslib_MoveWMCursor;
+    _this->CheckMouseMode = NULL;//os2fslib_CheckMouseMode;
+  } else
+  {
+    // We'll have software mouse cursor in FS mode!
+    _this->FreeWMCursor = os2fslib_FreeWMCursor;
+    _this->CreateWMCursor = os2fslib_CreateWMCursor_FS;
+    _this->ShowWMCursor = os2fslib_ShowWMCursor;
+    _this->WarpWMCursor = os2fslib_WarpWMCursor;
+    _this->MoveWMCursor = os2fslib_MoveWMCursor;
+    _this->CheckMouseMode = NULL;//os2fslib_CheckMouseMode;
+  }
+}
+
+static void os2fslib_InitOSKeymap(_THIS)
+{
+  int i;
+
+  iShiftIsPressed = 0;
+
+  /* Map the VK and CH keysyms */
+  for ( i=0; i<=255; ++i )
+    HWScanKeyMap[i] = SDLK_UNKNOWN;
+
+  // First line of keyboard:
+  HWScanKeyMap[0x1] = SDLK_ESCAPE;
+  HWScanKeyMap[0x3b] = SDLK_F1;
+  HWScanKeyMap[0x3c] = SDLK_F2;
+  HWScanKeyMap[0x3d] = SDLK_F3;
+  HWScanKeyMap[0x3e] = SDLK_F4;
+  HWScanKeyMap[0x3f] = SDLK_F5;
+  HWScanKeyMap[0x40] = SDLK_F6;
+  HWScanKeyMap[0x41] = SDLK_F7;
+  HWScanKeyMap[0x42] = SDLK_F8;
+  HWScanKeyMap[0x43] = SDLK_F9;
+  HWScanKeyMap[0x44] = SDLK_F10;
+  HWScanKeyMap[0x57] = SDLK_F11;
+  HWScanKeyMap[0x58] = SDLK_F12;
+  HWScanKeyMap[0x5d] = SDLK_PRINT;
+  HWScanKeyMap[0x46] = SDLK_SCROLLOCK;
+  HWScanKeyMap[0x5f] = SDLK_PAUSE;
+
+  // Second line of keyboard:
+  HWScanKeyMap[0x29] = SDLK_BACKQUOTE;
+  HWScanKeyMap[0x2] = SDLK_1;
+  HWScanKeyMap[0x3] = SDLK_2;
+  HWScanKeyMap[0x4] = SDLK_3;
+  HWScanKeyMap[0x5] = SDLK_4;
+  HWScanKeyMap[0x6] = SDLK_5;
+  HWScanKeyMap[0x7] = SDLK_6;
+  HWScanKeyMap[0x8] = SDLK_7;
+  HWScanKeyMap[0x9] = SDLK_8;
+  HWScanKeyMap[0xa] = SDLK_9;
+  HWScanKeyMap[0xb] = SDLK_0;
+  HWScanKeyMap[0xc] = SDLK_MINUS;
+  HWScanKeyMap[0xd] = SDLK_EQUALS;
+  HWScanKeyMap[0xe] = SDLK_BACKSPACE;
+  HWScanKeyMap[0x68] = SDLK_INSERT;
+  HWScanKeyMap[0x60] = SDLK_HOME;
+  HWScanKeyMap[0x62] = SDLK_PAGEUP;
+  HWScanKeyMap[0x45] = SDLK_NUMLOCK;
+  HWScanKeyMap[0x5c] = SDLK_KP_DIVIDE;
+  HWScanKeyMap[0x37] = SDLK_KP_MULTIPLY;
+  HWScanKeyMap[0x4a] = SDLK_KP_MINUS;
+
+  // Third line of keyboard:
+  HWScanKeyMap[0xf] = SDLK_TAB;
+  HWScanKeyMap[0x10] = SDLK_q;
+  HWScanKeyMap[0x11] = SDLK_w;
+  HWScanKeyMap[0x12] = SDLK_e;
+  HWScanKeyMap[0x13] = SDLK_r;
+  HWScanKeyMap[0x14] = SDLK_t;
+  HWScanKeyMap[0x15] = SDLK_y;
+  HWScanKeyMap[0x16] = SDLK_u;
+  HWScanKeyMap[0x17] = SDLK_i;
+  HWScanKeyMap[0x18] = SDLK_o;
+  HWScanKeyMap[0x19] = SDLK_p;
+  HWScanKeyMap[0x1a] = SDLK_LEFTBRACKET;
+  HWScanKeyMap[0x1b] = SDLK_RIGHTBRACKET;
+  HWScanKeyMap[0x1c] = SDLK_RETURN;
+  HWScanKeyMap[0x69] = SDLK_DELETE;
+  HWScanKeyMap[0x65] = SDLK_END;
+  HWScanKeyMap[0x67] = SDLK_PAGEDOWN;
+  HWScanKeyMap[0x47] = SDLK_KP7;
+  HWScanKeyMap[0x48] = SDLK_KP8;
+  HWScanKeyMap[0x49] = SDLK_KP9;
+  HWScanKeyMap[0x4e] = SDLK_KP_PLUS;
+
+  // Fourth line of keyboard:
+  HWScanKeyMap[0x3a] = SDLK_CAPSLOCK;
+  HWScanKeyMap[0x1e] = SDLK_a;
+  HWScanKeyMap[0x1f] = SDLK_s;
+  HWScanKeyMap[0x20] = SDLK_d;
+  HWScanKeyMap[0x21] = SDLK_f;
+  HWScanKeyMap[0x22] = SDLK_g;
+  HWScanKeyMap[0x23] = SDLK_h;
+  HWScanKeyMap[0x24] = SDLK_j;
+  HWScanKeyMap[0x25] = SDLK_k;
+  HWScanKeyMap[0x26] = SDLK_l;
+  HWScanKeyMap[0x27] = SDLK_SEMICOLON;
+  HWScanKeyMap[0x28] = SDLK_QUOTE;
+  HWScanKeyMap[0x2b] = SDLK_BACKSLASH;
+  HWScanKeyMap[0x4b] = SDLK_KP4;
+  HWScanKeyMap[0x4c] = SDLK_KP5;
+  HWScanKeyMap[0x4d] = SDLK_KP6;
+
+  // Fifth line of keyboard:
+  HWScanKeyMap[0x2a] = SDLK_LSHIFT;
+  HWScanKeyMap[0x56] = SDLK_WORLD_1; // Code 161, letter i' on hungarian keyboard
+  HWScanKeyMap[0x2c] = SDLK_z;
+  HWScanKeyMap[0x2d] = SDLK_x;
+  HWScanKeyMap[0x2e] = SDLK_c;
+  HWScanKeyMap[0x2f] = SDLK_v;
+  HWScanKeyMap[0x30] = SDLK_b;
+  HWScanKeyMap[0x31] = SDLK_n;
+  HWScanKeyMap[0x32] = SDLK_m;
+  HWScanKeyMap[0x33] = SDLK_COMMA;
+  HWScanKeyMap[0x34] = SDLK_PERIOD;
+  HWScanKeyMap[0x35] = SDLK_SLASH;
+  HWScanKeyMap[0x36] = SDLK_RSHIFT;
+  HWScanKeyMap[0x61] = SDLK_UP;
+  HWScanKeyMap[0x4f] = SDLK_KP1;
+  HWScanKeyMap[0x50] = SDLK_KP2;
+  HWScanKeyMap[0x51] = SDLK_KP3;
+  HWScanKeyMap[0x5a] = SDLK_KP_ENTER;
+
+  // Sixth line of keyboard:
+  HWScanKeyMap[0x1d] = SDLK_LCTRL;
+  HWScanKeyMap[0x7e] = SDLK_LSUPER; // Windows key
+  HWScanKeyMap[0x38] = SDLK_LALT;
+  HWScanKeyMap[0x39] = SDLK_SPACE;
+  HWScanKeyMap[0x5e] = SDLK_RALT;// Actually, altgr on my keyboard...
+  HWScanKeyMap[0x7f] = SDLK_RSUPER;
+  HWScanKeyMap[0x7c] = SDLK_MENU;
+  HWScanKeyMap[0x5b] = SDLK_RCTRL;
+  HWScanKeyMap[0x63] = SDLK_LEFT;
+  HWScanKeyMap[0x66] = SDLK_DOWN;
+  HWScanKeyMap[0x64] = SDLK_RIGHT;
+  HWScanKeyMap[0x52] = SDLK_KP0;
+  HWScanKeyMap[0x53] = SDLK_KP_PERIOD;
+}
+
+
+/* Iconify the window.
+ This function returns 1 if there is a window manager and the
+ window was actually iconified, it returns 0 otherwise.
+ */
+int os2fslib_IconifyWindow(_THIS)
+{
+  HAB hab;
+  HMQ hmq;
+  ERRORID hmqerror;
+
+  // If there is no more window, nothing we can do!
+  if (_this->hidden->iPMThreadStatus!=1) return 0;
+
+  // Cannot do anything in fullscreen mode!
+  if (FSLib_QueryFSMode(_this->hidden->hwndClient))
+    return 0;
+
+  // Make sure this thread is prepared for using the Presentation Manager!
+  hab = WinInitialize(0);
+  hmq = WinCreateMsgQueue(hab,0);
+  // Remember if there was an error at WinCreateMsgQueue(), because we don't
+  // want to destroy somebody else's queue later. :)
+  hmqerror = WinGetLastError(hab);
+
+  WinSetWindowPos(_this->hidden->hwndFrame, HWND_TOP,
+		 0, 0, 0, 0, SWP_MINIMIZE);
+
+  // Now destroy the message queue, if we've created it!
+  if (ERRORIDERROR(hmqerror)==0)
+    WinDestroyMsgQueue(hmq);
+
+  return 1;
+}
+
+static SDL_GrabMode os2fslib_GrabInput(_THIS, SDL_GrabMode mode)
+{
+  HAB hab;
+  HMQ hmq;
+  ERRORID hmqerror;
+
+
+  // If there is no more window, nothing we can do!
+  if (_this->hidden->iPMThreadStatus!=1)
+    return SDL_GRAB_OFF;
+
+  // Make sure this thread is prepared for using the Presentation Manager!
+  hab = WinInitialize(0);
+  hmq = WinCreateMsgQueue(hab,0);
+  // Remember if there was an error at WinCreateMsgQueue(), because we don't
+  // want to destroy somebody else's queue later. :)
+  hmqerror = WinGetLastError(hab);
+
+
+  if (mode == SDL_GRAB_OFF)
+  {
+#ifdef DEBUG_BUILD
+    printf("[os2fslib_GrabInput] : Releasing mouse\n"); fflush(stdout);
+#endif
+
+    // Release the mouse
+    bMouseCapturable = 0;
+    if (bMouseCaptured)
+    {
+      WinSetCapture(HWND_DESKTOP, NULLHANDLE);
+      bMouseCaptured = 0;
+    }
+  } else
+  {
+#ifdef DEBUG_BUILD
+    printf("[os2fslib_GrabInput] : Capturing mouse\n"); fflush(stdout);
+#endif
+
+    // Capture the mouse
+    bMouseCapturable = 1;
+    if (WinQueryFocus(HWND_DESKTOP) == _this->hidden->hwndClient)
+    {
+      WinSetCapture(HWND_DESKTOP, _this->hidden->hwndClient);
+      bMouseCaptured = 1;
+      {
+        SWP swpClient;
+        POINTL ptl;
+        // Center the mouse to the middle of the window!
+        WinQueryWindowPos(_this->hidden->hwndClient, &swpClient);
+        ptl.x = 0; ptl.y = 0;
+        WinMapWindowPoints(_this->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
+        _this->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account!  */
+        WinSetPointerPos(HWND_DESKTOP,
+                         ptl.x + swpClient.cx/2,
+                         ptl.y + swpClient.cy/2);
+      }
+    }
+  }
+
+  // Now destroy the message queue, if we've created it!
+  if (ERRORIDERROR(hmqerror)==0)
+    WinDestroyMsgQueue(hmq);
+
+  return mode;
+}
+
+/* Set the title and icon text */
+static void os2fslib_SetCaption(_THIS, const char *title, const char *icon)
+{
+  HAB hab;
+  HMQ hmq;
+  ERRORID hmqerror;
+
+  // If there is no more window, nothing we can do!
+  if (_this->hidden->iPMThreadStatus!=1) return;
+
+  // Make sure this thread is prepared for using the Presentation Manager!
+  hab = WinInitialize(0);
+  hmq = WinCreateMsgQueue(hab,0);
+  // Remember if there was an error at WinCreateMsgQueue(), because we don't
+  // want to destroy somebody else's queue later. :)
+  hmqerror = WinGetLastError(hab);
+
+  WinSetWindowText(_this->hidden->hwndFrame, (char *) title);
+
+  // Now destroy the message queue, if we've created it!
+  if (ERRORIDERROR(hmqerror)==0)
+    WinDestroyMsgQueue(hmq);
+}
+
+static int os2fslib_ToggleFullScreen(_THIS, int on)
+{
+#ifdef DEBUG_BUILD
+  printf("[os2fslib_ToggleFullScreen] : %d\n", on); fflush(stdout);
+#endif
+  // If there is no more window, nothing we can do!
+  if (_this->hidden->iPMThreadStatus!=1) return 0;
+
+  FSLib_ToggleFSMode(_this->hidden->hwndClient, on);
+  /* Cursor manager functions to Windowed/FS mode*/
+  os2fslib_SetCursorManagementFunctions(_this, !on);
+  return 1;
+}
+
+/* This is called after the video mode has been set, to get the
+ initial mouse state.  It should queue events as necessary to
+ properly represent the current mouse focus and position.
+ */
+static void os2fslib_UpdateMouse(_THIS)
+{
+  POINTL ptl;
+  HAB hab;
+  HMQ hmq;
+  ERRORID hmqerror;
+  SWP swpClient;
+
+  // If there is no more window, nothing we can do!
+  if (_this->hidden->iPMThreadStatus!=1) return;
+
+
+  // Make sure this thread is prepared for using the Presentation Manager!
+  hab = WinInitialize(0);
+  hmq = WinCreateMsgQueue(hab,0);
+  // Remember if there was an error at WinCreateMsgQueue(), because we don't
+  // want to destroy somebody else's queue later. :)
+  hmqerror = WinGetLastError(hab);
+
+  
+
+  if (_this->hidden->fInFocus)
+  {
+    // If our app is in focus
+    SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
+    SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS);
+    SDL_PrivateAppActive(1, SDL_APPACTIVE);
+    WinQueryPointerPos(HWND_DESKTOP, &ptl);
+    WinMapWindowPoints(HWND_DESKTOP, _this->hidden->hwndClient, &ptl, 1);
+    WinQueryWindowPos(_this->hidden->hwndClient, &swpClient);
+    // Convert OS/2 mouse position to SDL position, and also scale it!
+    ptl.x = ptl.x * _this->hidden->SrcBufferDesc.uiXResolution / swpClient.cx;
+    ptl.y = ptl.y * _this->hidden->SrcBufferDesc.uiYResolution / swpClient.cy;
+    ptl.y = _this->hidden->SrcBufferDesc.uiYResolution - ptl.y - 1;
+    SDL_PrivateMouseMotion(0, 0, (Sint16) (ptl.x), (Sint16) (ptl.y));
+  } else
+  {
+    // If we're not in focus
+    SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
+    SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS);
+    SDL_PrivateAppActive(0, SDL_APPACTIVE);
+    SDL_PrivateMouseMotion(0, 0, (Sint16) -1, (Sint16) -1);
+  }
+
+  // Now destroy the message queue, if we've created it!
+  if (ERRORIDERROR(hmqerror)==0)
+    WinDestroyMsgQueue(hmq);
+
+}
+
+/* This pointer should exist in the native video subsystem and should
+ point to an appropriate update function for the current video mode
+ */
+static void os2fslib_UpdateRects(_THIS, int numrects, SDL_Rect *rects)
+{
+  // If there is no more window, nothing we can do!
+  if (_this->hidden->iPMThreadStatus!=1) return;
+
+#ifdef BITBLT_IN_WINMESSAGEPROC
+  WinSendMsg(_this->hidden->hwndClient,
+                 WM_UPDATERECTSREQUEST,
+                 (MPARAM) numrects,
+                 (MPARAM) rects);
+#else
+  if (DosRequestMutexSem(_this->hidden->hmtxUseSrcBuffer, SEM_INDEFINITE_WAIT)==NO_ERROR)
+  {
+    int i;
+
+    if (_this->hidden->pSDLSurface)
+    {
+#ifndef RESIZE_EVEN_IF_RESIZABLE
+      SWP swp;
+      // But only blit if the window is not resizable, or if
+      // the window is resizable and the source buffer size is the
+      // same as the destination buffer size!
+      WinQueryWindowPos(_this->hidden->hwndClient, &swp);
+      if ((_this->hidden->pSDLSurface) &&
+          (_this->hidden->pSDLSurface->flags & SDL_RESIZABLE) &&
+          ((swp.cx != _this->hidden->SrcBufferDesc.uiXResolution) ||
+           (swp.cy != _this->hidden->SrcBufferDesc.uiYResolution)
+          ) &&
+          (!FSLib_QueryFSMode(_this->hidden->hwndClient))
+         )
+      {
+        // Resizable surface and in resizing!
+        // So, don't blit now!
+#ifdef DEBUG_BUILD
+        printf("[UpdateRects] : Skipping blit while resizing!\n"); fflush(stdout);
+#endif
+      } else
+#endif
+      {
+      /*
+        // Blit the whole window
+        FSLIB_BITBLT(_this->hidden->hwndClient, _this->hidden->pchSrcBuffer,
+                     0, 0,
+                     _this->hidden->SrcBufferDesc.uiXResolution,
+                     _this->hidden->SrcBufferDesc.uiYResolution);
+                     */
+#ifdef DEBUG_BUILD
+          printf("[os2fslib_UpdateRects] : Blitting!\n"); fflush(stdout);
+#endif
+  
+        // Blit the changed areas
+        for (i=0; i<numrects; i++)
+          FSLIB_BITBLT(_this->hidden->hwndClient, _this->hidden->pchSrcBuffer,
+                       rects[i].y, rects[i].x, rects[i].w, rects[i].h);
+      }
+    }
+#ifdef DEBUG_BUILD
+     else
+       printf("[os2fslib_UpdateRects] : No public surface!\n"); fflush(stdout);
+#endif
+    DosReleaseMutexSem(_this->hidden->hmtxUseSrcBuffer);
+  }
+#ifdef DEBUG_BUILD
+  else
+    printf("[os2fslib_UpdateRects] : Error in mutex!\n"); fflush(stdout);
+#endif
+#endif
+}
+
+
+/* Reverse the effects VideoInit() -- called if VideoInit() fails
+ or if the application is shutting down the video subsystem.
+ */
+static void os2fslib_VideoQuit(_THIS)
+{
+#ifdef DEBUG_BUILD
+  printf("[os2fslib_VideoQuit]\n"); fflush(stdout);
+#endif
+  // Close PM stuff if running!
+  if (_this->hidden->iPMThreadStatus == 1)
+  {
+    int iTimeout;
+    WinPostMsg(_this->hidden->hwndFrame, WM_QUIT, (MPARAM) 0, (MPARAM) 0);
+    // HACK: We had this line before:
+    //DosWaitThread((TID *) &(_this->hidden->tidPMThread), DCWW_WAIT);
+    // We don't use it, because the PMThread will never stop, or if it stops,
+    // it will kill the whole process as a emergency fallback.
+    // So, we only check for the iPMThreadStatus stuff!
+#ifdef DEBUG_BUILD
+    printf("[os2fslib_VideoQuit] : Waiting for PM thread to die\n"); fflush(stdout);
+#endif
+
+    iTimeout=0;
+    while ((_this->hidden->iPMThreadStatus == 1) && (iTimeout<100))
+    {
+      iTimeout++;
+      DosSleep(64);
+    }
+
+#ifdef DEBUG_BUILD
+    printf("[os2fslib_VideoQuit] : End of wait.\n"); fflush(stdout);
+#endif
+
+    if (_this->hidden->iPMThreadStatus == 1)
+    {
+#ifdef DEBUG_BUILD
+      printf("[os2fslib_VideoQuit] : Killing PM thread!\n"); fflush(stdout);
+#endif
+      
+      _this->hidden->iPMThreadStatus = 0;
+      DosKillThread(_this->hidden->tidPMThread);
+
+      if (_this->hidden->hwndFrame)
+      {
+#ifdef DEBUG_BUILD
+        printf("[os2fslib_VideoQuit] : Destroying PM window!\n"); fflush(stdout);
+#endif
+
+        WinDestroyWindow(_this->hidden->hwndFrame); _this->hidden->hwndFrame=NULL;
+      }
+    }
+
+  }
+
+  // Free result of an old ListModes() call, because there is
+  // no FreeListModes() call in SDL!
+  if (_this->hidden->pListModesResult)
+  {
+    free(_this->hidden->pListModesResult); _this->hidden->pListModesResult = NULL;
+  }
+
+  // Free list of available fullscreen modes
+  if (_this->hidden->pAvailableFSLibVideoModes)
+  {
+    FSLib_FreeVideoModeList(_this->hidden->pAvailableFSLibVideoModes);
+    _this->hidden->pAvailableFSLibVideoModes = NULL;
+  }
+
+  // Free application icon if we had one
+  if (hptrCurrentIcon)
+  {
+    WinDestroyPointer(hptrCurrentIcon);
+    hptrCurrentIcon = NULL;
+  }
+}
+
+/* Set the requested video mode, returning a surface which will be
+ set to the SDL_VideoSurface.  The width and height will already
+ be verified by ListModes(), and the video subsystem is free to
+ set the mode to a supported bit depth different from the one
+ specified -- the desired bpp will be emulated with a shadow
+ surface if necessary.  If a new mode is returned, this function
+ should take care of cleaning up the current mode.
+ */
+static SDL_Surface *os2fslib_SetVideoMode(_THIS, SDL_Surface *current,
+					  int width, int height, int bpp, Uint32 flags)
+{
+  static int bFirstCall = 1;
+  FSLib_VideoMode_p pModeInfo, pModeInfoFound;
+  FSLib_VideoMode TempModeInfo;
+  HAB hab;
+  HMQ hmq;
+  ERRORID hmqerror;
+  RECTL rectl;
+  SDL_Surface *pResult;
+
+  // If there is no more window, nothing we can do!
+  if (_this->hidden->iPMThreadStatus!=1) return NULL;
+
+#ifdef DEBUG_BUILD
+  printf("[os2fslib_SetVideoMode] : Request for %dx%d @ %dBPP, flags=0x%x\n", width, height, bpp, flags); fflush(stdout);
+#endif
+
+  // We don't support palette modes!
+  if (bpp==8) bpp=32;
+
+  // Also, we don't support resizable modes in fullscreen mode.
+  if (flags & SDL_RESIZABLE)
+    flags &= ~SDL_FULLSCREEN;
+
+  // No double buffered mode
+  if (flags & SDL_DOUBLEBUF)
+    flags &= ~SDL_DOUBLEBUF;
+
+  // And, we don't support HWSURFACE yet.
+  if (flags & SDL_HWSURFACE)
+  {
+    flags &= ~SDL_HWSURFACE;
+    flags |= SDL_SWSURFACE;
+  }
+
+#ifdef DEBUG_BUILD
+  printf("[os2fslib_SetVideoMode] : Changed request to %dx%d @ %dBPP, flags=0x%x\n", width, height, bpp, flags); fflush(stdout);
+#endif
+
+  // First check if there is such a video mode they want!
+  pModeInfoFound = NULL;
+
+  // For fullscreen mode we don't support every resolution!
+  // So, go through the video modes, and check for such a resolution!
+  pModeInfoFound = NULL;
+  pModeInfo = _this->hidden->pAvailableFSLibVideoModes;
+
+  while (pModeInfo)
+  {
+    // Check all available fullscreen modes for this resolution
+    if ((pModeInfo->uiXResolution == width) &&
+        (pModeInfo->uiYResolution == height) &&
+        (pModeInfo->uiBPP!=8)) // palettized modes not yet supported
+    {
+      // If good resolution, try to find the exact BPP, or at least
+      // something similar...
+      if (!pModeInfoFound)
+        pModeInfoFound = pModeInfo;
+      else
+      if ((pModeInfoFound->uiBPP!=bpp) &&
+          (pModeInfoFound->uiBPP<pModeInfo->uiBPP))
+        pModeInfoFound = pModeInfo;
+    }
+    pModeInfo = pModeInfo->pNext;
+  }
+
+  // If we did not find a good fullscreen mode, then try a similar
+  if (!pModeInfoFound)
+  {
+#ifdef DEBUG_BUILD
+    printf("[os2fslib_SetVideoMode] : Requested video mode not found, looking for a similar one!\n"); fflush(stdout);
+#endif
+    // Go through the video modes again, and find a similar resolution!
+    pModeInfo = _this->hidden->pAvailableFSLibVideoModes;
+    while (pModeInfo)
+    {
+      // Check all available fullscreen modes for this resolution
+      if ((pModeInfo->uiXResolution >= width) &&
+          (pModeInfo->uiYResolution >= height) &&
+          (pModeInfo->uiBPP == bpp))
+      {
+        if (!pModeInfoFound)
+          pModeInfoFound = pModeInfo;
+        else
+        if (((pModeInfoFound->uiXResolution-width)*(pModeInfoFound->uiYResolution-height))>
+            ((pModeInfo->uiXResolution-width)*(pModeInfo->uiYResolution-height)))
+        {
+          // Found a mode which is closer than the current one
+          pModeInfoFound = pModeInfo;
+        }
+      }
+      pModeInfo = pModeInfo->pNext;
+    }
+  }
+
+  // If we did not find a good fullscreen mode, then return NULL
+  if (!pModeInfoFound)
+  {
+#ifdef DEBUG_BUILD
+    printf("[os2fslib_SetVideoMode] : Requested video mode not found!\n"); fflush(stdout);
+#endif
+    return NULL;
+  }
+
+#ifdef DEBUG_BUILD
+  printf("[os2fslib_SetVideoMode] : Found mode!\n"); fflush(stdout);
+#endif
+
+  // We'll possibly adjust the structure, so copy out the values
+  // into TempModeInfo!
+  memcpy(&TempModeInfo, pModeInfoFound, sizeof(TempModeInfo));
+  pModeInfoFound = &TempModeInfo;
+
+  if (flags & SDL_RESIZABLE)
+  {
+#ifdef DEBUG_BUILD
+    printf("[os2fslib_SetVideoMode] : Requested mode is resizable, changing width/height\n"); fflush(stdout);
+#endif
+    // Change width and height to requested one!
+    TempModeInfo.uiXResolution = width;
+    TempModeInfo.uiYResolution = height;
+    TempModeInfo.uiScanLineSize = width * ((TempModeInfo.uiBPP+7)/8);
+  }
+
+  // We can try create new surface!
+
+  // Make sure this thread is prepared for using the Presentation Manager!
+  hab = WinInitialize(0);
+  hmq = WinCreateMsgQueue(hab,0);
+  // Remember if there was an error at WinCreateMsgQueue(), because we don't
+  // want to destroy somebody else's queue later. :)
+  hmqerror = WinGetLastError(hab);
+
+  
+
+  if (DosRequestMutexSem(_this->hidden->hmtxUseSrcBuffer, SEM_INDEFINITE_WAIT)==NO_ERROR)
+  {
+#ifdef DEBUG_BUILD
+    printf("[os2fslib_SetVideoMode] : Creating new SW surface\n"); fflush(stdout);
+#endif
+
+    // Create new software surface!
+    pResult = SDL_CreateRGBSurface(SDL_SWSURFACE,
+                                   pModeInfoFound->uiXResolution,
+                                   pModeInfoFound->uiYResolution,
+                                   pModeInfoFound->uiBPP,
+                                   ((unsigned int) pModeInfoFound->PixelFormat.ucRedMask) << pModeInfoFound->PixelFormat.ucRedPosition,
+                                   ((unsigned int) pModeInfoFound->PixelFormat.ucGreenMask) << pModeInfoFound->PixelFormat.ucGreenPosition,
+                                   ((unsigned int) pModeInfoFound->PixelFormat.ucBlueMask) << pModeInfoFound->PixelFormat.ucBluePosition,
+                                   ((unsigned int) pModeInfoFound->PixelFormat.ucAlphaMask) << pModeInfoFound->PixelFormat.ucAlphaPosition);
+
+    if (pResult == NULL)
+    {
+      DosReleaseMutexSem(_this->hidden->hmtxUseSrcBuffer);
+      SDL_OutOfMemory();
+      return NULL;
+    }
+
+#ifdef DEBUG_BUILD
+    printf("[os2fslib_SetVideoMode] : Adjusting pixel format\n"); fflush(stdout);
+#endif
+
+    // Adjust pixel format mask!
+    pResult->format->Rmask = ((unsigned int) pModeInfoFound->PixelFormat.ucRedMask) << pModeInfoFound->PixelFormat.ucRedPosition;
+    pResult->format->Rshift = pModeInfoFound->PixelFormat.ucRedPosition;
+    pResult->format->Rloss = pModeInfoFound->PixelFormat.ucRedAdjust;
+    pResult->format->Gmask = ((unsigned int) pModeInfoFound->PixelFormat.ucGreenMask) << pModeInfoFound->PixelFormat.ucGreenPosition;
+    pResult->format->Gshift = pModeInfoFound->PixelFormat.ucGreenPosition;
+    pResult->format->Gloss = pModeInfoFound->PixelFormat.ucGreenAdjust;
+    pResult->format->Bmask = ((unsigned int) pModeInfoFound->PixelFormat.ucBlueMask) << pModeInfoFound->PixelFormat.ucBluePosition;
+    pResult->format->Bshift = pModeInfoFound->PixelFormat.ucBluePosition;
+    pResult->format->Bloss = pModeInfoFound->PixelFormat.ucBlueAdjust;
+    pResult->format->Amask = ((unsigned int) pModeInfoFound->PixelFormat.ucAlphaMask) << pModeInfoFound->PixelFormat.ucAlphaPosition;
+    pResult->format->Ashift = pModeInfoFound->PixelFormat.ucAlphaPosition;
+    pResult->format->Aloss = pModeInfoFound->PixelFormat.ucAlphaAdjust;
+
+#ifdef REPORT_EMPTY_ALPHA_MASK
+    pResult->format->Amask =
+        pResult->format->Ashift =
+        pResult->format->Aloss = 0;
+#endif
+
+    // Adjust surface flags
+    pResult->flags |= (flags & SDL_FULLSCREEN);
+    pResult->flags |= (flags & SDL_RESIZABLE);
+
+    // It might be that the software surface pitch is not the same as
+    // the pitch we have, so adjust that!
+    pModeInfoFound->uiScanLineSize = pResult->pitch;
+
+    // Store new source buffer parameters!
+    memcpy(&(_this->hidden->SrcBufferDesc), pModeInfoFound, sizeof(*pModeInfoFound));
+    _this->hidden->pchSrcBuffer = pResult->pixels;
+
+#ifdef DEBUG_BUILD
+    printf("[os2fslib_SetVideoMode] : Telling FSLib the stuffs\n"); fflush(stdout);
+#endif
+
+    // Tell the FSLib window the new source image format
+    FSLib_SetSrcBufferDesc(_this->hidden->hwndClient, &(_this->hidden->SrcBufferDesc));
+
+    if (
+        ((flags & SDL_RESIZABLE)==0) ||
+        (bFirstCall)
+       )
+    {
+      bFirstCall = 0;
+#ifdef DEBUG_BUILD
+      printf("[os2fslib_SetVideoMode] : Modifying window size\n"); fflush(stdout);
+#endif
+
+      // Calculate frame window size from client window size
+      rectl.xLeft = 0;
+      rectl.yBottom = 0;
+      rectl.xRight = pModeInfoFound->uiXResolution; // Noninclusive
+      rectl.yTop = pModeInfoFound->uiYResolution; // Noninclusive
+      WinCalcFrameRect(_this->hidden->hwndFrame, &rectl, FALSE);
+
+      // Set the new size of the main window
+      SetAccessableWindowPos(_this->hidden->hwndFrame,
+                             HWND_TOP,
+                             0, 0,
+                             (rectl.xRight-rectl.xLeft),
+                             (rectl.yTop-rectl.yBottom),
+                             SWP_SIZE | SWP_ACTIVATE | SWP_SHOW);
+    }
+
+    // Set fullscreen mode flag, and switch to fullscreen if needed!
+    if (flags & SDL_FULLSCREEN)
+    {
+#ifdef DEBUG_BUILD
+      printf("[os2fslib_SetVideoMode] : Also trying to switch to fullscreen\n");
+      fflush(stdout);
+#endif
+      FSLib_ToggleFSMode(_this->hidden->hwndClient, 1);
+      /* Cursor manager functions to FS mode*/
+      os2fslib_SetCursorManagementFunctions(_this, 0);
+    } else
+    {
+#ifdef DEBUG_BUILD
+      printf("[os2fslib_SetVideoMode] : Also trying to switch to desktop mode\n");
+      fflush(stdout);
+#endif
+      FSLib_ToggleFSMode(_this->hidden->hwndClient, 0);
+      /* Cursor manager functions to Windowed mode*/
+      os2fslib_SetCursorManagementFunctions(_this, 1);
+    }
+
+    _this->hidden->pSDLSurface = pResult;
+
+    DosReleaseMutexSem(_this->hidden->hmtxUseSrcBuffer);
+  } else
+  {
+#ifdef DEBUG_BUILD
+    printf("[os2fslib_SetVideoMode] : Could not get hmtxUseSrcBuffer!\n"); fflush(stdout);
+#endif
+    
+    pResult = NULL;
+  }
+
+  // As we have the new surface, we don't need the current one anymore!
+  if ((pResult) && (current))
+  {
+#ifdef DEBUG_BUILD
+    printf("[os2fslib_SetVideoMode] : Freeing old surface\n"); fflush(stdout);
+#endif
+    SDL_FreeSurface(current);
+  }
+
+  // Redraw window
+  WinInvalidateRegion(_this->hidden->hwndClient, NULL, TRUE);
+
+  // Now destroy the message queue, if we've created it!
+  if (ERRORIDERROR(hmqerror)==0)
+  {
+#ifdef DEBUG_BUILD
+    printf("[os2fslib_SetVideoMode] : Destroying message queue\n"); fflush(stdout);
+#endif
+    WinDestroyMsgQueue(hmq);
+  }
+
+#ifdef DEBUG_BUILD
+  printf("[os2fslib_SetVideoMode] : Done\n"); fflush(stdout);
+#endif
+
+  /* We're done */
+
+  // Return with the new surface!
+  return pResult;
+}
+
+/* List the available video modes for the given pixel format, sorted
+ from largest to smallest.
+ */
+static SDL_Rect **os2fslib_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
+{
+#ifdef DEBUG_BUILD
+  printf("[os2fslib_ListModes] : ListModes of %d Bpp\n", format->BitsPerPixel);
+#endif
+  // Destroy result of previous call, if there is any
+  if (_this->hidden->pListModesResult)
+  {
+    free(_this->hidden->pListModesResult); _this->hidden->pListModesResult = NULL;
+  }
+
+  // For resizable and windowed mode we support every resolution!
+  if ((flags & SDL_RESIZABLE) && ((flags & SDL_FULLSCREEN) == 0))
+    return (SDL_Rect **)-1;
+
+  // Check if they need fullscreen or non-fullscreen video modes!
+  if ((flags & SDL_FULLSCREEN) == 0)
+
+  {
+    // For windowed mode we support every resolution!
+    return (SDL_Rect **)-1;
+  } else
+  {
+    FSLib_VideoMode_p pFSMode;
+    // For fullscreen mode we don't support every resolution!
+    // Now create a new list
+    pFSMode = _this->hidden->pAvailableFSLibVideoModes;
+    while (pFSMode)
+    {
+      if (pFSMode->uiBPP == format->BitsPerPixel)
+      {
+        SDL_Rect *pRect = (SDL_Rect *) malloc(sizeof(SDL_Rect));
+        if (pRect)
+        {
+          // Fill description
+          pRect->x = 0;
+          pRect->y = 0;
+          pRect->w = pFSMode->uiXResolution;
+          pRect->h = pFSMode->uiYResolution;
+#ifdef DEBUG_BUILD
+//          printf("!!! Seems to be good!\n");
+//	  printf("F: %dx%d\n", pRect->w, pRect->h);
+#endif
+          // And insert into list of pRects
+          if (!(_this->hidden->pListModesResult))
+          {
+#ifdef DEBUG_BUILD
+//            printf("!!! Inserting to beginning\n");
+#endif
+
+            // We're the first one to be inserted!
+            _this->hidden->pListModesResult = (SDL_Rect**) malloc(2*sizeof(SDL_Rect*));
+            if (_this->hidden->pListModesResult)
+            {
+              _this->hidden->pListModesResult[0] = pRect;
+	      _this->hidden->pListModesResult[1] = NULL;
+            } else
+            {
+              free(pRect);
+            }
+          } else
+          {
+            // We're not the first ones, so find the place where we
+            // have to insert ourselves
+            SDL_Rect **pNewList;
+            int iPlace, iNumOfSlots, i;
+
+#ifdef DEBUG_BUILD
+//            printf("!!! Searching where to insert\n");
+#endif
+
+            iPlace = -1; iNumOfSlots = 1; // Count the last NULL too!
+            for (i=0; _this->hidden->pListModesResult[i]; i++)
+            {
+              iNumOfSlots++;
+              if (iPlace==-1)
+              {
+                if ((_this->hidden->pListModesResult[i]->w*_this->hidden->pListModesResult[i]->h)<
+                    (pRect->w*pRect->h))
+                {
+                  iPlace = i;
+                }
+              }
+            }
+            if (iPlace==-1) iPlace = iNumOfSlots-1;
+
+#ifdef DEBUG_BUILD
+//            printf("!!! From %d slots, it will be at %d\n", iNumOfSlots, iPlace);
+#endif
+
+            pNewList = (SDL_Rect**) realloc(_this->hidden->pListModesResult, (iNumOfSlots+1)*sizeof(SDL_Rect*));
+            if (pNewList)
+            {
+              for (i=iNumOfSlots;i>iPlace;i--)
+                pNewList[i] = pNewList[i-1];
+              pNewList[iPlace] = pRect;
+              _this->hidden->pListModesResult = pNewList;
+            } else
+            {
+              free(pRect);
+            }
+          }
+        }
+      }
+      pFSMode = pFSMode->pNext;
+    }
+  }
+#ifdef DEBUG_BUILD
+//  printf("Returning list\n");
+#endif
+  return _this->hidden->pListModesResult;
+}
+
+/* Initialize the native video subsystem, filling 'vformat' with the
+ "best" display pixel format, returning 0 or -1 if there's an error.
+ */
+static int os2fslib_VideoInit(_THIS, SDL_PixelFormat *vformat)
+{
+  FSLib_VideoMode_p pDesktopMode;
+
+#ifdef DEBUG_BUILD
+  printf("[os2fslib_VideoInit] : Enter\n"); fflush(stdout);
+#endif
+
+  // Report the best pixel format. For this,
+  // we'll use the current desktop format.
+  pDesktopMode = FSLib_GetDesktopVideoMode();
+  if (!pDesktopMode)
+  {
+    SDL_SetError("Could not query desktop video mode!");
+#ifdef DEBUG_BUILD
+    printf("[os2fslib_VideoInit] : Could not query desktop video mode!\n");
+#endif
+    return -1;
+  }
+
+  /* Determine the screen depth */
+  vformat->BitsPerPixel = pDesktopMode->uiBPP;
+  vformat->BytesPerPixel = (vformat->BitsPerPixel+7)/8;
+
+  vformat->Rmask = ((unsigned int) pDesktopMode->PixelFormat.ucRedMask) << pDesktopMode->PixelFormat.ucRedPosition;
+  vformat->Rshift = pDesktopMode->PixelFormat.ucRedPosition;
+  vformat->Rloss = pDesktopMode->PixelFormat.ucRedAdjust;
+  vformat->Gmask = ((unsigned int) pDesktopMode->PixelFormat.ucGreenMask) << pDesktopMode->PixelFormat.ucGreenPosition;
+  vformat->Gshift = pDesktopMode->PixelFormat.ucGreenPosition;
+  vformat->Gloss = pDesktopMode->PixelFormat.ucGreenAdjust;
+  vformat->Bmask = ((unsigned int) pDesktopMode->PixelFormat.ucBlueMask) << pDesktopMode->PixelFormat.ucBluePosition;
+  vformat->Bshift = pDesktopMode->PixelFormat.ucBluePosition;
+  vformat->Bloss = pDesktopMode->PixelFormat.ucBlueAdjust;
+  vformat->Amask = ((unsigned int) pDesktopMode->PixelFormat.ucAlphaMask) << pDesktopMode->PixelFormat.ucAlphaPosition;
+  vformat->Ashift = pDesktopMode->PixelFormat.ucAlphaPosition;
+  vformat->Aloss = pDesktopMode->PixelFormat.ucAlphaAdjust;
+
+#ifdef REPORT_EMPTY_ALPHA_MASK
+  vformat->Amask =
+      vformat->Ashift =
+      vformat->Aloss = 0;
+#endif
+
+  // Fill in some window manager capabilities
+  _this->info.wm_available = 1;
+
+  // Initialize some internal variables
+  _this->hidden->pListModesResult = NULL;
+  _this->hidden->fInFocus = 0;
+  _this->hidden->iSkipWMMOUSEMOVE = 0;
+  _this->hidden->iMouseVisible = 1;
+  DosCreateMutexSem(NULL, &(_this->hidden->hmtxUseSrcBuffer), 0, FALSE);
+
+  // Now create our window with a default size
+
+  // For this, we select the first available fullscreen mode as
+  // current window size!
+  memcpy(&(_this->hidden->SrcBufferDesc), _this->hidden->pAvailableFSLibVideoModes, sizeof(_this->hidden->SrcBufferDesc));
+  // Allocate new video buffer!
+  _this->hidden->pchSrcBuffer = (char *) malloc(_this->hidden->pAvailableFSLibVideoModes->uiScanLineSize * _this->hidden->pAvailableFSLibVideoModes->uiYResolution);
+  if (!_this->hidden->pchSrcBuffer)
+  {
+#ifdef DEBUG_BUILD
+    printf("[os2fslib_VideoInit] : Yikes, not enough memory for new video buffer!\n"); fflush(stdout);
+#endif
+    SDL_SetError("Not enough memory for new video buffer!\n");
+    return -1;
+  }
+
+  // For this, we need a message processing thread.
+  // We'll create a new thread for this, which will do everything
+  // what is related to PM
+  _this->hidden->iPMThreadStatus = 0;
+  _this->hidden->tidPMThread = _beginthread(PMThreadFunc, NULL, 65536, (void *) _this);
+  if (_this->hidden->tidPMThread <= 0)
+  {
+#ifdef DEBUG_BUILD
+    printf("[os2fslib_VideoInit] : Could not create PM thread!\n");
+#endif
+    SDL_SetError("Could not create PM thread");
+    return -1;
+  }
+#ifdef USE_DOSSETPRIORITY
+  // Burst the priority of PM Thread!
+  DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, _this->hidden->tidPMThread);
+#endif
+  // Wait for the PM thread to initialize!
+  while (_this->hidden->iPMThreadStatus==0)
+    DosSleep(32);
+  // If the PM thread could not set up everything, then
+  // report an error!
+  if (_this->hidden->iPMThreadStatus!=1)
+  {
+#ifdef DEBUG_BUILD
+    printf("[os2fslib_VideoInit] : PMThread reported an error : %d\n", _this->hidden->iPMThreadStatus);
+#endif
+    SDL_SetError("Error initializing PM thread");
+    return -1;
+  }
+
+  return 0;
+}
+
+
+static void os2fslib_DeleteDevice(_THIS)
+{
+#ifdef DEBUG_BUILD
+  printf("[os2fslib_DeleteDevice]\n"); fflush(stdout);
+#endif
+  // Free used memory
+  FSLib_FreeVideoModeList(_this->hidden->pAvailableFSLibVideoModes);
+  if (_this->hidden->pListModesResult)
+    free(_this->hidden->pListModesResult);
+  if (_this->hidden->pchSrcBuffer)
+    free(_this->hidden->pchSrcBuffer);
+  DosCloseMutexSem(_this->hidden->hmtxUseSrcBuffer);
+  free(_this->hidden);
+  free(_this);
+  FSLib_Uninitialize();
+}
+
+static int os2fslib_Available(void)
+{
+
+  // If we can run, it means that we could load FSLib,
+  // so we assume that it's available then!
+  return 1;
+}
+
+static void os2fslib_MorphToPM()
+{
+  PPIB pib;
+  PTIB tib;
+
+  DosGetInfoBlocks(&tib, &pib);
+
+  // Change flag from VIO to PM:
+  if (pib->pib_ultype==2) pib->pib_ultype = 3;
+}
+
+static SDL_VideoDevice *os2fslib_CreateDevice(int devindex)
+{
+  SDL_VideoDevice *device;
+
+#ifdef DEBUG_BUILD
+  printf("[os2fslib_CreateDevice] : Enter\n"); fflush(stdout);
+#endif
+
+  /* Initialize all variables that we clean on shutdown */
+  device = (SDL_VideoDevice *)malloc(sizeof(SDL_VideoDevice));
+  if ( device )
+  {
+    memset(device, 0, (sizeof *device));
+    // Also allocate memory for private data
+    device->hidden = (struct SDL_PrivateVideoData *) malloc((sizeof(struct SDL_PrivateVideoData)));
+  }
+  if ( (device == NULL) || (device->hidden == NULL) )
+  {
+    SDL_OutOfMemory();
+    if ( device )
+      free(device);
+    return NULL;
+  }
+  memset(device->hidden, 0, (sizeof *device->hidden));
+
+  /* Set the function pointers */
+#ifdef DEBUG_BUILD
+  printf("[os2fslib_CreateDevice] : VideoInit is %p\n", os2fslib_VideoInit); fflush(stdout);
+#endif
+
+  /* Initialization/Query functions */
+  device->VideoInit = os2fslib_VideoInit;
+  device->ListModes = os2fslib_ListModes;
+  device->SetVideoMode = os2fslib_SetVideoMode;
+  device->ToggleFullScreen = os2fslib_ToggleFullScreen;
+  device->UpdateMouse = os2fslib_UpdateMouse;
+  device->CreateYUVOverlay = NULL;
+  device->SetColors = os2fslib_SetColors;
+  device->UpdateRects = os2fslib_UpdateRects;
+  device->VideoQuit = os2fslib_VideoQuit;
+  /* Hardware acceleration functions */
+  device->AllocHWSurface = os2fslib_AllocHWSurface;
+  device->CheckHWBlit = NULL;
+  device->FillHWRect = NULL;
+  device->SetHWColorKey = NULL;
+  device->SetHWAlpha = NULL;
+  device->LockHWSurface = os2fslib_LockHWSurface;
+  device->UnlockHWSurface = os2fslib_UnlockHWSurface;
+  device->FlipHWSurface = NULL;
+  device->FreeHWSurface = os2fslib_FreeHWSurface;
+  /* Window manager functions */
+  device->SetCaption = os2fslib_SetCaption;
+  device->SetIcon = os2fslib_SetIcon;
+  device->IconifyWindow = os2fslib_IconifyWindow;
+  device->GrabInput = os2fslib_GrabInput;
+  device->GetWMInfo = NULL;
+  /* Cursor manager functions to Windowed mode*/
+  os2fslib_SetCursorManagementFunctions(device, 1);
+  /* Event manager functions */
+  device->InitOSKeymap = os2fslib_InitOSKeymap;
+  device->PumpEvents = os2fslib_PumpEvents;
+  /* The function used to dispose of this structure */
+  device->free = os2fslib_DeleteDevice;
+
+  // Make sure we'll be able to use Win* API even if the application
+  // was linked to be a VIO application!
+  os2fslib_MorphToPM();
+
+  // Now initialize FSLib, and query available video modes!
+  if (!FSLib_Initialize())
+  {
+    // Could not initialize FSLib!
+#ifdef DEBUG_BUILD
+    printf("[os2fslib_CreateDevice] : Could not initialize FSLib!\n");
+#endif
+    SDL_SetError("Could not initialize FSLib!");
+    free(device->hidden);
+    free(device);
+    return NULL;
+  }
+  device->hidden->pAvailableFSLibVideoModes =
+    FSLib_GetVideoModeList();
+
+  return device;
+}
+
+VideoBootStrap OS2FSLib_bootstrap = {
+  	"os2fslib", "OS/2 Video Output using FSLib",
+	os2fslib_Available, os2fslib_CreateDevice
+};
+