Home | History | Annotate | Download | only in os2fslib
      1 /*
      2     SDL - Simple DirectMedia Layer
      3     Copyright (C) 1997-2012 Sam Lantinga
      4 
      5     This library is free software; you can redistribute it and/or
      6     modify it under the terms of the GNU Library General Public
      7     License as published by the Free Software Foundation; either
      8     version 2 of the License, or (at your option) any later version.
      9 
     10     This library is distributed in the hope that it will be useful,
     11     but WITHOUT ANY WARRANTY; without even the implied warranty of
     12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
     13     Library General Public License for more details.
     14 
     15     You should have received a copy of the GNU Library General Public
     16     License along with this library; if not, write to the Free
     17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
     18 
     19     Sam Lantinga
     20     slouken (at) libsdl.org
     21 */
     22 #include "SDL_config.h"
     23 
     24 #define _ULS_CALLCONV_
     25 #define CALLCONV _System
     26 #include <unidef.h>                    // Unicode API
     27 #include <uconv.h>                     // Unicode API (codepage conversion)
     28 
     29 #include <process.h>
     30 #include <time.h>
     31 
     32 #include "SDL_video.h"
     33 #include "SDL_mouse.h"
     34 #include "../SDL_sysvideo.h"
     35 #include "../SDL_pixels_c.h"
     36 #include "../../events/SDL_events_c.h"
     37 
     38 #include "SDL_os2fslib.h"
     39 
     40 static ULONG ulFCFToUse =
     41         FCF_TITLEBAR |
     42         FCF_SYSMENU |
     43         FCF_MINBUTTON |
     44         FCF_MAXBUTTON |
     45         FCF_NOBYTEALIGN |
     46         FCF_SIZEBORDER |
     47         FCF_TASKLIST;
     48 
     49 static int bMouseCaptured   = 0;
     50 static int bMouseCapturable = 0;
     51 static HPOINTER hptrGlobalPointer = NULL;
     52 static HPOINTER hptrCurrentIcon = NULL;
     53 static int iWindowSizeX = 320;
     54 static int iWindowSizeY = 200;
     55 static int bWindowResized = 0;
     56 
     57 #pragma pack(1)
     58 typedef struct BMPINFO
     59 {
     60    BITMAPINFO;
     61    RGB  clr;
     62 } BMPINFO, *PBMPINFO;
     63 #pragma pack()
     64 
     65 
     66 // Backdoors:
     67 DECLSPEC void SDLCALL SDL_OS2FSLIB_SetFCFToUse(ULONG ulFCF)
     68 {
     69   ulFCFToUse = ulFCF;
     70 }
     71 
     72 // Configuration defines:
     73 
     74 // We have to report empty alpha mask, otherwise SDL will select
     75 // alpha blitters, and this will have unwanted results, as we don't
     76 // support alpha channel in FSLib yet.
     77 #define REPORT_EMPTY_ALPHA_MASK
     78 
     79 // Experimental: Move every FSLib_BitBlt() call into window message
     80 // processing function.
     81 // This may fix dirt left on desktop. Or not.
     82 //#define BITBLT_IN_WINMESSAGEPROC
     83 
     84 // Experimental-2: Use WinLockWindowUpdate() in around bitblts!
     85 // This is not enabled, because it seems to cause more problems
     86 // than good.
     87 //#define USE_WINLOCKWINDOWUPDATE_AROUND_BITBLTS
     88 
     89 // Use the following to show resized image instead of black stuff
     90 // even if the surface is resizable.
     91 //#define RESIZE_EVEN_IF_RESIZABLE
     92 
     93 /* The translation table from a VK keysym to a SDL keysym */
     94 static SDLKey HWScanKeyMap[256];
     95 static SDL_keysym *TranslateKey(int vkey, int chcode, int scancode, SDL_keysym *keysym, int iPressed);
     96 static int  iShiftIsPressed;
     97 
     98 #ifdef BITBLT_IN_WINMESSAGEPROC
     99 #define WM_UPDATERECTSREQUEST   WM_USER+50
    100 #endif
    101 
    102 #ifdef USE_WINLOCKWINDOWUPDATE_AROUND_BITBLTS
    103 #define FSLIB_BITBLT(hwnd, buffer, top, left, width, height) \
    104     { \
    105       WinLockWindowUpdate(HWND_DESKTOP, HWND_DESKTOP); \
    106       FSLib_BitBlt(hwnd, buffer, top, left, width, height); \
    107       WinLockWindowUpdate(HWND_DESKTOP, NULL); \
    108     }
    109 #else
    110 #define FSLIB_BITBLT(hwnd, buffer, top, left, width, height) \
    111     FSLib_BitBlt(hwnd, buffer, top, left, width, height);
    112 #endif
    113 
    114 /////////////////////////////////////////////////////////////////////
    115 //
    116 // SetAccessableWindowPos
    117 //
    118 // Same as WinSetWindowPos(), but takes care for the window to be
    119 // always on the screen, the titlebar will be accessable everytime.
    120 //
    121 /////////////////////////////////////////////////////////////////////
    122 static BOOL SetAccessableWindowPos(HWND hwnd, HWND hwndInsertBehind,
    123                                    LONG x, LONG y,
    124                                    LONG cx, LONG cy,
    125                                    ULONG fl)
    126 {
    127   SWP swpDesktop, swp;
    128   // Get desktop area
    129   WinQueryWindowPos(HWND_DESKTOP, &swpDesktop);
    130 
    131   if ((fl & SWP_MOVE) && (fl & SWP_SIZE))
    132   {
    133     // If both moving and sizing, then change size and pos now!!
    134     if (x+cx>swpDesktop.cx)
    135       x = swpDesktop.cx - cx;
    136     if (x<0)
    137       x = 0;
    138     if (y<0)
    139       y = 0;
    140     if (y+cy>swpDesktop.cy)
    141       y = swpDesktop.cy - cy;
    142     return WinSetWindowPos(hwnd, hwndInsertBehind, x, y, cx, cy, fl);
    143   } else
    144   if (fl & SWP_MOVE)
    145   {
    146     // Just moving
    147     WinQueryWindowPos(hwnd, &swp);
    148     if (x+swp.cx>swpDesktop.cx)
    149       x = swpDesktop.cx - swp.cx;
    150     if (x<0)
    151       x = 0;
    152     if (y<0)
    153       y = 0;
    154     if (y+swp.cy>swpDesktop.cy)
    155       y = swpDesktop.cy - swp.cy;
    156     return WinSetWindowPos(hwnd, hwndInsertBehind, x, y, cx, cy, fl);
    157   } else
    158   if (fl & SWP_SIZE)
    159   {
    160     // Just sizing
    161     WinQueryWindowPos(hwnd, &swp);
    162     x = swp.x;
    163     y = swp.y;
    164     if (x+cx>swpDesktop.cx)
    165       x = swpDesktop.cx - cx;
    166     if (x<0)
    167       x = 0;
    168     if (y<0)
    169       y = 0;
    170     if (y+cy>swpDesktop.cy)
    171       y = swpDesktop.cy - cy;
    172     return WinSetWindowPos(hwnd, hwndInsertBehind, x, y, cx, cy, fl | SWP_MOVE);
    173   } else
    174   return WinSetWindowPos(hwnd, hwndInsertBehind, x, y, cx, cy, fl);
    175 }
    176 
    177 static UniChar NativeCharToUniChar(int chcode)
    178 {
    179   UniChar ucResult = (UniChar) chcode;
    180   int rc;
    181   UconvObject ucoTemp;
    182   char     achFrom[2];
    183   char     *pchFrom;
    184   size_t   iFromCount;
    185   UniChar  aucTo[10];
    186   UniChar  *pucTo;
    187   size_t   iToCount;
    188   size_t   iNonIdentical;
    189 
    190   // Create unicode convert object
    191   rc = UniCreateUconvObject(L"", &ucoTemp);
    192   if (rc!=ULS_SUCCESS)
    193   {
    194     // Could not create convert object!
    195     return ucResult;
    196   }
    197 
    198   // Convert language code string to unicode string
    199   achFrom[0] = (char) chcode;
    200   achFrom[1] = 0;
    201   iFromCount = sizeof(char) * 2;
    202   iToCount = sizeof(UniChar) * 2;
    203   pucTo = &(aucTo[0]);
    204   pchFrom = &(achFrom[0]);
    205 
    206   rc = UniUconvToUcs(ucoTemp,
    207                      &pchFrom,
    208                      &iFromCount,
    209                      &pucTo,
    210                      &iToCount,
    211                      &iNonIdentical);
    212 
    213   if (rc!=ULS_SUCCESS)
    214   {
    215     // Could not convert language code to UCS string!
    216     UniFreeUconvObject(ucoTemp);
    217     return ucResult;
    218   }
    219 
    220   UniFreeUconvObject(ucoTemp);
    221 
    222 #ifdef DEBUG_BUILD
    223   printf("%02x converted to %02x\n", (int) chcode, (int) (aucTo[0]));
    224 #endif
    225 
    226   return aucTo[0];
    227 }
    228 
    229 /////////////////////////////////////////////////////////////////////
    230 //
    231 // TranslateKey
    232 //
    233 // This creates SDL Keycodes from VK_ and hardware scan codes
    234 //
    235 /////////////////////////////////////////////////////////////////////
    236 static SDL_keysym *TranslateKey(int vkey, int chcode, int scancode, SDL_keysym *keysym, int iPressed)
    237 {
    238   keysym->scancode = (unsigned char) scancode;
    239   keysym->mod = KMOD_NONE;
    240   keysym->unicode = 0;
    241 
    242   if (iPressed && SDL_TranslateUNICODE)
    243   {
    244     if (chcode)
    245       keysym->unicode = NativeCharToUniChar(chcode);
    246     else
    247       keysym->unicode = vkey;
    248   }
    249 
    250   keysym->sym = HWScanKeyMap[scancode];
    251 
    252   // Now stuffs based on state of shift key(s)!
    253   if (vkey == VK_SHIFT)
    254   {
    255     iShiftIsPressed = iPressed;
    256   }
    257 
    258   if ((iShiftIsPressed) && (SDL_TranslateUNICODE))
    259   {
    260     // Change syms, if Unicode stuff is required
    261     // I think it's silly, but it's SDL...
    262     switch (keysym->sym)
    263     {
    264       case SDLK_BACKQUOTE:
    265         keysym->sym = '~';
    266         break;
    267       case SDLK_1:
    268         keysym->sym = SDLK_EXCLAIM;
    269         break;
    270       case SDLK_2:
    271         keysym->sym = SDLK_AT;
    272         break;
    273       case SDLK_3:
    274         keysym->sym = SDLK_HASH;
    275         break;
    276       case SDLK_4:
    277         keysym->sym = SDLK_DOLLAR;
    278         break;
    279       case SDLK_5:
    280         keysym->sym = '%';
    281         break;
    282       case SDLK_6:
    283         keysym->sym = SDLK_CARET;
    284         break;
    285       case SDLK_7:
    286         keysym->sym = SDLK_AMPERSAND;
    287         break;
    288       case SDLK_8:
    289         keysym->sym = SDLK_ASTERISK;
    290         break;
    291       case SDLK_9:
    292         keysym->sym = SDLK_LEFTPAREN;
    293         break;
    294       case SDLK_0:
    295         keysym->sym = SDLK_RIGHTPAREN;
    296         break;
    297       case SDLK_MINUS:
    298         keysym->sym = SDLK_UNDERSCORE;
    299         break;
    300       case SDLK_PLUS:
    301         keysym->sym = SDLK_EQUALS;
    302         break;
    303 
    304       case SDLK_LEFTBRACKET:
    305         keysym->sym = '{';
    306         break;
    307       case SDLK_RIGHTBRACKET:
    308         keysym->sym = '}';
    309         break;
    310 
    311       case SDLK_SEMICOLON:
    312         keysym->sym = SDLK_COLON;
    313         break;
    314       case SDLK_QUOTE:
    315         keysym->sym = SDLK_QUOTEDBL;
    316         break;
    317       case SDLK_BACKSLASH:
    318         keysym->sym = '|';
    319         break;
    320 
    321       case SDLK_COMMA:
    322         keysym->sym = SDLK_LESS;
    323         break;
    324       case SDLK_PERIOD:
    325         keysym->sym = SDLK_GREATER;
    326         break;
    327       case SDLK_SLASH:
    328         keysym->sym = SDLK_QUESTION;
    329         break;
    330 
    331       default:
    332         break;
    333     }
    334   }
    335   return keysym;
    336 }
    337 
    338 #define CONVERTMOUSEPOSITION()  \
    339         /* We have to inverse the mouse position, because every non-os/2 system */                                                \
    340         /* has a coordinate system where the (0;0) is the top-left corner,      */                                                \
    341         /* while on os/2 it's the bottom left corner!                           */                                                \
    342         if (FSLib_QueryFSMode(hwnd))                                                                                              \
    343         {                                                                                                                         \
    344           /* We're in FS mode!                                                        */                                          \
    345           /* In FS mode our window is as big as fullscreen mode, but not necessary as */                                          \
    346           /* big as the source buffer (can be bigger)                                 */                                          \
    347           /* So, limit mouse pos to source buffer size!                               */                                          \
    348           if (ppts->x<0) ppts->x = 0;                                                                                             \
    349           if (ppts->y<0) ppts->y = 0;                                                                                             \
    350           if (ppts->x>=pVideo->hidden->SrcBufferDesc.uiXResolution) ppts->x = pVideo->hidden->SrcBufferDesc.uiXResolution-1;      \
    351           if (ppts->y>=pVideo->hidden->SrcBufferDesc.uiYResolution) ppts->y = pVideo->hidden->SrcBufferDesc.uiYResolution-1;      \
    352           pVideo->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account!  */                                   \
    353           ptl.x = ppts->x; ptl.y = ppts->y;                                                                                       \
    354           WinMapWindowPoints(pVideo->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);                                                  \
    355           WinSetPointerPos(HWND_DESKTOP, ptl.x, ptl.y);                                                                           \
    356           /* Then convert OS/2 position to SDL position */                                                                        \
    357           ppts->y = pVideo->hidden->SrcBufferDesc.uiYResolution - ppts->y - 1;                                                    \
    358         } else                                                                                                                    \
    359         {                                                                                                                         \
    360           SWP swpClient;                                                                                                          \
    361           /* We're in windowed mode! */                                                                                           \
    362           WinQueryWindowPos(pVideo->hidden->hwndClient, &swpClient);                                                              \
    363           /* Convert OS/2 mouse position to SDL position, and also scale it! */                                                   \
    364           (ppts->x) = (ppts->x) * pVideo->hidden->SrcBufferDesc.uiXResolution / swpClient.cx;                                       \
    365           (ppts->y) = (ppts->y) * pVideo->hidden->SrcBufferDesc.uiYResolution / swpClient.cy;                                       \
    366           (ppts->y) = pVideo->hidden->SrcBufferDesc.uiYResolution - (ppts->y)  - 1;                                                 \
    367         }
    368 
    369 
    370 
    371 /////////////////////////////////////////////////////////////////////
    372 //
    373 // WndProc
    374 //
    375 // This is the message processing window procedure for the
    376 // SDLWindowClass, which is the client window in our application.
    377 // It handles switching back and away from the app (taking care of
    378 // going out and back to and from fullscreen mode), sending keystrokes
    379 // and mouse events to where it has to be sent, etc...
    380 //
    381 /////////////////////////////////////////////////////////////////////
    382 static MRESULT EXPENTRY WndProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
    383 {
    384   HPS ps;
    385   RECTL rcl;
    386   SDL_VideoDevice *pVideo = NULL;
    387 
    388   switch (msg)
    389   {
    390     case WM_CHAR:  // Keypress notification
    391 #ifdef DEBUG_BUILD
    392 //      printf("WM_CHAR\n"); fflush(stdout);
    393 #endif
    394       pVideo = WinQueryWindowPtr(hwnd, 0);
    395       if (pVideo)
    396       {
    397         /*
    398         // We skip repeated keys:
    399         if (CHARMSG(&msg)->cRepeat>1)
    400         {
    401 #ifdef DEBUG_BUILD
    402 //          printf("Repeated key (%d), skipping...\n", CHARMSG(&msg)->cRepeat); fflush(stdout);
    403 #endif
    404           return (MRESULT) TRUE;
    405         }
    406         */
    407 
    408         // If it's not repeated, then let's see if its pressed or released!
    409         if (SHORT1FROMMP(mp1) & KC_KEYUP)
    410         {
    411           // A key has been released
    412           SDL_keysym keysym;
    413 
    414 #ifdef DEBUG_BUILD
    415 //          printf("WM_CHAR, keyup, code is [0x%0x]\n", CHAR4FROMMP(mp1)); // HW scan code
    416 #endif
    417 
    418           // One problem is with F1, which gets only the keyup message because
    419           // it is a system key.
    420           // So, when we get keyup message, we simulate keydown too!
    421           // UPDATE:
    422           //  This problem should be solved now, that the accelerator keys are
    423           //  disabled for this window!
    424           /*
    425           if (SHORT2FROMMP(mp2)==VK_F1)
    426           {
    427             SDL_PrivateKeyboard(SDL_PRESSED, TranslateKey(SHORT2FROMMP(mp2), // VK_ code
    428                                                            SHORT1FROMMP(mp2), // Character code
    429                                                            CHAR4FROMMP(mp1),  // HW Scan code
    430                                                            &keysym,0));
    431           }*/
    432 
    433           SDL_PrivateKeyboard(SDL_RELEASED, TranslateKey(SHORT2FROMMP(mp2), // VK_ code
    434                                                          SHORT1FROMMP(mp2), // Character code
    435                                                          CHAR4FROMMP(mp1),  // HW Scan code
    436                                                          &keysym,0));
    437 
    438         } else
    439         {
    440           // A key has been pressed
    441           SDL_keysym keysym;
    442 
    443 #ifdef DEBUG_BUILD
    444 //          printf("WM_CHAR, keydown, code is [0x%0x]\n", CHAR4FROMMP(mp1)); // HW scan code
    445 #endif
    446           // Check for fastkeys: ALT+HOME to toggle FS mode
    447           //                     ALT+END to close app
    448           if ((SHORT1FROMMP(mp1) & KC_ALT) &&
    449               (SHORT2FROMMP(mp2) == VK_HOME))
    450           {
    451 #ifdef DEBUG_BUILD
    452             printf(" Pressed ALT+HOME!\n"); fflush(stdout);
    453 #endif
    454             // Only switch between fullscreen and back if it's not
    455             // a resizable mode!
    456             if (
    457                 (!pVideo->hidden->pSDLSurface) ||
    458                 ((pVideo->hidden->pSDLSurface)
    459                  && ((pVideo->hidden->pSDLSurface->flags & SDL_RESIZABLE)==0)
    460                 )
    461                )
    462               FSLib_ToggleFSMode(hwnd, !FSLib_QueryFSMode(hwnd));
    463 #ifdef DEBUG_BUILD
    464             else
    465               printf(" Resizable mode, so discarding ALT+HOME!\n"); fflush(stdout);
    466 #endif
    467           } else
    468           if ((SHORT1FROMMP(mp1) & KC_ALT) &&
    469               (SHORT2FROMMP(mp2) == VK_END))
    470           {
    471 #ifdef DEBUG_BUILD
    472             printf(" Pressed ALT+END!\n"); fflush(stdout);
    473 #endif
    474             // Close window, and get out of loop!
    475             // Also send event to SDL application, but we won't
    476             // wait for it to be processed!
    477             SDL_PrivateQuit();
    478             WinPostMsg(hwnd, WM_QUIT, 0, 0);
    479           } else
    480           {
    481 
    482             SDL_PrivateKeyboard(SDL_PRESSED, TranslateKey(SHORT2FROMMP(mp2), // VK_ code
    483                                                           SHORT1FROMMP(mp2), // Character code
    484                                                           CHAR4FROMMP(mp1),  // HW Scan code
    485                                                           &keysym,1));
    486 
    487           }
    488         }
    489       }
    490       return (MRESULT) TRUE;
    491 
    492     case WM_TRANSLATEACCEL:
    493       {
    494         PQMSG pqmsg;
    495         pqmsg = (PQMSG) mp1;
    496         if (mp1)
    497         {
    498           if (pqmsg->msg == WM_CHAR)
    499           {
    500             // WM_CHAR message!
    501             // Let's filter the ALT keypress and all other acceleration keys!
    502             return (MRESULT) FALSE;
    503           }
    504         }
    505         break; // Default processing (pass to parent until frame control)
    506       }
    507 
    508     case WM_PAINT:  // Window redraw!
    509 #ifdef DEBUG_BUILD
    510       printf("WM_PAINT (0x%x)\n", hwnd); fflush(stdout);
    511 #endif
    512       ps = WinBeginPaint(hwnd,0,&rcl);
    513       pVideo = FSLib_GetUserParm(hwnd);
    514       if (pVideo)
    515       {
    516         if (!pVideo->hidden->pSDLSurface)
    517         {
    518           RECTL rclRect;
    519           // So, don't blit now!
    520 #ifdef DEBUG_BUILD
    521           printf("WM_PAINT : Skipping blit while resizing (Pre!)!\n"); fflush(stdout);
    522 #endif
    523           WinQueryWindowRect(hwnd, &rclRect);
    524           // Fill with black
    525           WinFillRect(ps, &rclRect, CLR_BLACK);
    526         } else
    527         {
    528           if (DosRequestMutexSem(pVideo->hidden->hmtxUseSrcBuffer, 1000)==NO_ERROR)
    529           {
    530             int iTop, iLeft, iWidth, iHeight;
    531             int iXScaleError, iYScaleError;
    532             int iXScaleError2, iYScaleError2;
    533             SWP swp;
    534 
    535             // Re-blit the modified area!
    536             // For this, we have to calculate the points, scaled!
    537             WinQueryWindowPos(hwnd, &swp);
    538 #ifdef DEBUG_BUILD
    539             printf("WM_PAINT : WinSize: %d %d, BufSize: %d %d\n",
    540                    swp.cx,
    541                    swp.cy,
    542                    pVideo->hidden->SrcBufferDesc.uiXResolution,
    543                    pVideo->hidden->SrcBufferDesc.uiYResolution
    544                   );
    545             fflush(stdout);
    546 #endif
    547 
    548 #ifndef RESIZE_EVEN_IF_RESIZABLE
    549             // But only blit if the window is not resizable, or if
    550             // the window is resizable and the source buffer size is the
    551             // same as the destination buffer size!
    552             if ((!pVideo->hidden->pSDLSurface) ||
    553                 ((pVideo->hidden->pSDLSurface) &&
    554                  (pVideo->hidden->pSDLSurface->flags & SDL_RESIZABLE) &&
    555                  ((swp.cx != pVideo->hidden->SrcBufferDesc.uiXResolution) ||
    556                   (swp.cy != pVideo->hidden->SrcBufferDesc.uiYResolution)
    557                  ) &&
    558                  (!FSLib_QueryFSMode(hwnd))
    559                 )
    560                )
    561             {
    562               RECTL rclRect;
    563               // Resizable surface and in resizing!
    564               // So, don't blit now!
    565 #ifdef DEBUG_BUILD
    566               printf("WM_PAINT : Skipping blit while resizing!\n"); fflush(stdout);
    567 #endif
    568               WinQueryWindowRect(hwnd, &rclRect);
    569               // Fill with black
    570               WinFillRect(ps, &rclRect, CLR_BLACK);
    571             } else
    572 #endif
    573             {
    574 
    575               iXScaleError = (pVideo->hidden->SrcBufferDesc.uiXResolution-1) / swp.cx;
    576               iYScaleError = (pVideo->hidden->SrcBufferDesc.uiYResolution-1) / swp.cy;
    577               if (iXScaleError<0) iXScaleError = 0;
    578               if (iYScaleError<0) iYScaleError = 0;
    579               iXScaleError2 = (swp.cx-1)/(pVideo->hidden->SrcBufferDesc.uiXResolution);
    580               iYScaleError2 = (swp.cy-1)/(pVideo->hidden->SrcBufferDesc.uiYResolution);
    581               if (iXScaleError2<0) iXScaleError2 = 0;
    582               if (iYScaleError2<0) iYScaleError2 = 0;
    583 
    584               iTop = (swp.cy - rcl.yTop) * pVideo->hidden->SrcBufferDesc.uiYResolution / swp.cy - iYScaleError;
    585               iLeft = rcl.xLeft * pVideo->hidden->SrcBufferDesc.uiXResolution / swp.cx - iXScaleError;
    586               iWidth = ((rcl.xRight-rcl.xLeft) * pVideo->hidden->SrcBufferDesc.uiXResolution + swp.cx-1)
    587                 / swp.cx + 2*iXScaleError;
    588               iHeight = ((rcl.yTop-rcl.yBottom) * pVideo->hidden->SrcBufferDesc.uiYResolution + swp.cy-1)
    589                 / swp.cy + 2*iYScaleError;
    590 
    591               iWidth+=iXScaleError2;
    592               iHeight+=iYScaleError2;
    593 
    594               if (iTop<0) iTop = 0;
    595               if (iLeft<0) iLeft = 0;
    596               if (iTop+iHeight>pVideo->hidden->SrcBufferDesc.uiYResolution) iHeight = pVideo->hidden->SrcBufferDesc.uiYResolution-iTop;
    597               if (iLeft+iWidth>pVideo->hidden->SrcBufferDesc.uiXResolution) iWidth = pVideo->hidden->SrcBufferDesc.uiXResolution-iLeft;
    598 
    599 #ifdef DEBUG_BUILD
    600               printf("WM_PAINT : BitBlt: %d %d -> %d %d (Buf %d x %d)\n",
    601                      iTop, iLeft, iWidth, iHeight,
    602                      pVideo->hidden->SrcBufferDesc.uiXResolution,
    603                      pVideo->hidden->SrcBufferDesc.uiYResolution
    604                     );
    605               fflush(stdout);
    606 #endif
    607 
    608               FSLIB_BITBLT(hwnd, pVideo->hidden->pchSrcBuffer, iTop, iLeft, iWidth, iHeight);
    609             }
    610 
    611             DosReleaseMutexSem(pVideo->hidden->hmtxUseSrcBuffer);
    612           }
    613         }
    614       }
    615 #ifdef DEBUG_BUILD
    616       else
    617       {
    618         printf("WM_PAINT : No pVideo!\n"); fflush(stdout);
    619       }
    620 #endif
    621       WinEndPaint(ps);
    622 #ifdef DEBUG_BUILD
    623       printf("WM_PAINT : Done.\n");
    624       fflush(stdout);
    625 #endif
    626       return 0;
    627 
    628     case WM_SIZE:
    629       {
    630 #ifdef DEBUG_BUILD
    631         printf("WM_SIZE : (%d %d)\n",
    632                SHORT1FROMMP(mp2), SHORT2FROMMP(mp2)); fflush(stdout);
    633 #endif
    634         iWindowSizeX = SHORT1FROMMP(mp2);
    635         iWindowSizeY = SHORT2FROMMP(mp2);
    636         bWindowResized = 1;
    637 
    638         // Make sure the window will be redrawn
    639         WinInvalidateRegion(hwnd, NULL, TRUE);
    640       }
    641       break;
    642 
    643     case WM_FSLIBNOTIFICATION:
    644 #ifdef DEBUG_BUILD
    645         printf("WM_FSLIBNOTIFICATION\n"); fflush(stdout);
    646 #endif
    647       if ((int)mp1 == FSLN_TOGGLEFSMODE)
    648       {
    649         // FS mode changed, reblit image!
    650         pVideo = FSLib_GetUserParm(hwnd);
    651         if (pVideo)
    652         {
    653           if (!pVideo->hidden->pSDLSurface)
    654           {
    655             // Resizable surface and in resizing!
    656             // So, don't blit now!
    657 #ifdef DEBUG_BUILD
    658             printf("WM_FSLIBNOTIFICATION : Can not blit if there is no surface, doing nothing.\n"); fflush(stdout);
    659 #endif
    660           } else
    661           {
    662             if (DosRequestMutexSem(pVideo->hidden->hmtxUseSrcBuffer, 1000)==NO_ERROR)
    663             {
    664               if (pVideo->hidden->pSDLSurface)
    665               {
    666 #ifndef RESIZE_EVEN_IF_RESIZABLE
    667                 SWP swp;
    668 
    669                 // But only blit if the window is not resizable, or if
    670                 // the window is resizable and the source buffer size is the
    671                 // same as the destination buffer size!
    672                 WinQueryWindowPos(hwnd, &swp);
    673                 if ((!pVideo->hidden->pSDLSurface) ||
    674                     (
    675                      (pVideo->hidden->pSDLSurface) &&
    676                      (pVideo->hidden->pSDLSurface->flags & SDL_RESIZABLE) &&
    677                      ((swp.cx != pVideo->hidden->SrcBufferDesc.uiXResolution) ||
    678                       (swp.cy != pVideo->hidden->SrcBufferDesc.uiYResolution)
    679                      ) &&
    680                      (!FSLib_QueryFSMode(hwnd))
    681                     )
    682                    )
    683                 {
    684                   // Resizable surface and in resizing!
    685                   // So, don't blit now!
    686 #ifdef DEBUG_BUILD
    687                   printf("WM_FSLIBNOTIFICATION : Cannot blit while resizing, doing nothing.\n"); fflush(stdout);
    688 #endif
    689                 } else
    690 #endif
    691                 {
    692 #ifdef DEBUG_BUILD
    693                   printf("WM_FSLIBNOTIFICATION : Blitting!\n"); fflush(stdout);
    694 #endif
    695                   FSLIB_BITBLT(hwnd, pVideo->hidden->pchSrcBuffer,
    696                                0, 0,
    697                                pVideo->hidden->SrcBufferDesc.uiXResolution,
    698                                pVideo->hidden->SrcBufferDesc.uiYResolution);
    699                 }
    700               }
    701 #ifdef DEBUG_BUILD
    702               else
    703                 printf("WM_FSLIBNOTIFICATION : No public surface!\n"); fflush(stdout);
    704 #endif
    705 
    706               DosReleaseMutexSem(pVideo->hidden->hmtxUseSrcBuffer);
    707             }
    708           }
    709         }
    710       }
    711       return (MPARAM) 1;
    712 
    713     case WM_ACTIVATE:
    714 #ifdef DEBUG_BUILD
    715       printf("WM_ACTIVATE\n"); fflush(stdout);
    716 #endif
    717 
    718       pVideo = FSLib_GetUserParm(hwnd);
    719       if (pVideo)
    720       {
    721         pVideo->hidden->fInFocus = (int) mp1;
    722         if (pVideo->hidden->fInFocus)
    723         {
    724           // Went into focus
    725           if ((pVideo->hidden->iMouseVisible) && (!bMouseCaptured))
    726             WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE));
    727           else
    728             WinSetPointer(HWND_DESKTOP, NULL);
    729 
    730           if (bMouseCapturable)
    731           {
    732             // Re-capture the mouse, if we captured it before!
    733             WinSetCapture(HWND_DESKTOP, hwnd);
    734             bMouseCaptured = 1;
    735             {
    736               SWP swpClient;
    737               POINTL ptl;
    738               // Center the mouse to the middle of the window!
    739               WinQueryWindowPos(pVideo->hidden->hwndClient, &swpClient);
    740               ptl.x = 0; ptl.y = 0;
    741               WinMapWindowPoints(pVideo->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
    742               pVideo->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account!  */
    743               WinSetPointerPos(HWND_DESKTOP,
    744                                ptl.x + swpClient.cx/2,
    745                                ptl.y + swpClient.cy/2);
    746             }
    747           }
    748         } else
    749         {
    750           // Went out of focus
    751           WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE));
    752 
    753           if (bMouseCaptured)
    754           {
    755             // Release the mouse
    756             WinSetCapture(HWND_DESKTOP, hwnd);
    757             bMouseCaptured = 0;
    758           }
    759         }
    760       }
    761 #ifdef DEBUG_BUILD
    762       printf("WM_ACTIVATE done\n"); fflush(stdout);
    763 #endif
    764 
    765       break;
    766 
    767     case WM_BUTTON1DOWN:
    768 #ifdef DEBUG_BUILD
    769       printf("WM_BUTTON1DOWN\n"); fflush(stdout);
    770 #endif
    771 
    772       pVideo = FSLib_GetUserParm(hwnd);
    773       if (pVideo)
    774       {
    775         SDL_PrivateMouseButton(SDL_PRESSED,
    776                                SDL_BUTTON_LEFT,
    777                                0, 0); // Don't report mouse movement!
    778 
    779         if (bMouseCapturable)
    780         {
    781           // We should capture the mouse!
    782           if (!bMouseCaptured)
    783           {
    784             WinSetCapture(HWND_DESKTOP, hwnd);
    785             WinSetPointer(HWND_DESKTOP, NULL);
    786             bMouseCaptured = 1;
    787             {
    788               SWP swpClient;
    789               POINTL ptl;
    790               // Center the mouse to the middle of the window!
    791               WinQueryWindowPos(pVideo->hidden->hwndClient, &swpClient);
    792               ptl.x = 0; ptl.y = 0;
    793               WinMapWindowPoints(pVideo->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
    794               pVideo->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account!  */
    795               WinSetPointerPos(HWND_DESKTOP,
    796                                ptl.x + swpClient.cx/2,
    797                                ptl.y + swpClient.cy/2);
    798             }
    799           }
    800         }
    801       }
    802       break;
    803     case WM_BUTTON1UP:
    804 #ifdef DEBUG_BUILD
    805       printf("WM_BUTTON1UP\n"); fflush(stdout);
    806 #endif
    807       SDL_PrivateMouseButton(SDL_RELEASED,
    808                              SDL_BUTTON_LEFT,
    809                              0, 0); // Don't report mouse movement!
    810       break;
    811     case WM_BUTTON2DOWN:
    812 #ifdef DEBUG_BUILD
    813       printf("WM_BUTTON2DOWN\n"); fflush(stdout);
    814 #endif
    815 
    816       pVideo = FSLib_GetUserParm(hwnd);
    817       if (pVideo)
    818       {
    819         SDL_PrivateMouseButton(SDL_PRESSED,
    820                                SDL_BUTTON_RIGHT,
    821                                0, 0); // Don't report mouse movement!
    822 
    823         if (bMouseCapturable)
    824         {
    825           // We should capture the mouse!
    826           if (!bMouseCaptured)
    827           {
    828             WinSetCapture(HWND_DESKTOP, hwnd);
    829             WinSetPointer(HWND_DESKTOP, NULL);
    830             bMouseCaptured = 1;
    831             {
    832               SWP swpClient;
    833               POINTL ptl;
    834               // Center the mouse to the middle of the window!
    835               WinQueryWindowPos(pVideo->hidden->hwndClient, &swpClient);
    836               ptl.x = 0; ptl.y = 0;
    837               WinMapWindowPoints(pVideo->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
    838               pVideo->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account!  */
    839               WinSetPointerPos(HWND_DESKTOP,
    840                                ptl.x + swpClient.cx/2,
    841                                ptl.y + swpClient.cy/2);
    842             }
    843           }
    844         }
    845 
    846       }
    847       break;
    848     case WM_BUTTON2UP:
    849 #ifdef DEBUG_BUILD
    850       printf("WM_BUTTON2UP\n"); fflush(stdout);
    851 #endif
    852       SDL_PrivateMouseButton(SDL_RELEASED,
    853                              SDL_BUTTON_RIGHT,
    854                              0, 0); // Don't report mouse movement!
    855       break;
    856     case WM_BUTTON3DOWN:
    857 #ifdef DEBUG_BUILD
    858       printf("WM_BUTTON3DOWN\n"); fflush(stdout);
    859 #endif
    860 
    861       pVideo = FSLib_GetUserParm(hwnd);
    862       if (pVideo)
    863       {
    864         SDL_PrivateMouseButton(SDL_PRESSED,
    865                                SDL_BUTTON_MIDDLE,
    866                                0, 0); // Don't report mouse movement!
    867 
    868         if (bMouseCapturable)
    869         {
    870           // We should capture the mouse!
    871           if (!bMouseCaptured)
    872           {
    873             WinSetCapture(HWND_DESKTOP, hwnd);
    874             WinSetPointer(HWND_DESKTOP, NULL);
    875             bMouseCaptured = 1;
    876             {
    877               SWP swpClient;
    878               POINTL ptl;
    879               // Center the mouse to the middle of the window!
    880               WinQueryWindowPos(pVideo->hidden->hwndClient, &swpClient);
    881               ptl.x = 0; ptl.y = 0;
    882               WinMapWindowPoints(pVideo->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
    883               pVideo->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account!  */
    884               WinSetPointerPos(HWND_DESKTOP,
    885                                ptl.x + swpClient.cx/2,
    886                                ptl.y + swpClient.cy/2);
    887             }
    888           }
    889         }
    890       }
    891       break;
    892     case WM_BUTTON3UP:
    893 #ifdef DEBUG_BUILD
    894       printf("WM_BUTTON3UP\n"); fflush(stdout);
    895 #endif
    896       SDL_PrivateMouseButton(SDL_RELEASED,
    897                              SDL_BUTTON_MIDDLE,
    898                              0, 0); // Don't report mouse movement!
    899       break;
    900     case WM_MOUSEMOVE:
    901 #ifdef DEBUG_BUILD
    902 //      printf("WM_MOUSEMOVE\n"); fflush(stdout);
    903 #endif
    904 
    905       pVideo = FSLib_GetUserParm(hwnd);
    906       if (pVideo)
    907       {
    908         if (pVideo->hidden->iSkipWMMOUSEMOVE)
    909         {
    910           pVideo->hidden->iSkipWMMOUSEMOVE--;
    911         } else
    912         {
    913           POINTS *ppts = (POINTS *) (&mp1);
    914           POINTL ptl;
    915 
    916           if (bMouseCaptured)
    917           {
    918             SWP swpClient;
    919 
    920             WinQueryWindowPos(pVideo->hidden->hwndClient, &swpClient);
    921 
    922             // Send relative mouse position, and re-center the mouse
    923             // Reposition the mouse to the center of the screen/window
    924             SDL_PrivateMouseMotion(0, // Buttons not changed
    925                                    1, // Relative position
    926                                    ppts->x - (swpClient.cx/2),
    927                                    (swpClient.cy/2) - ppts->y);
    928 
    929             ptl.x = 0; ptl.y = 0;
    930             WinMapWindowPoints(pVideo->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
    931             pVideo->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account!  */
    932             // Center the mouse to the middle of the window!
    933             WinSetPointerPos(HWND_DESKTOP,
    934                              ptl.x + swpClient.cx/2,
    935                              ptl.y + swpClient.cy/2);
    936           } else
    937           {
    938             CONVERTMOUSEPOSITION();
    939 
    940             // Send absolute mouse position
    941             SDL_PrivateMouseMotion(0, // Buttons not changed
    942                                    0, // Absolute position
    943                                    ppts->x,
    944                                    ppts->y);
    945           }
    946         }
    947         if ((pVideo->hidden->iMouseVisible) && (!bMouseCaptured))
    948         {
    949 #ifdef DEBUG_BUILD
    950 //          printf("WM_MOUSEMOVE : ptr = %p\n", hptrGlobalPointer); fflush(stdout);
    951 #endif
    952 
    953           if (hptrGlobalPointer)
    954             WinSetPointer(HWND_DESKTOP, hptrGlobalPointer);
    955           else
    956             WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE));
    957         }
    958         else
    959         {
    960           WinSetPointer(HWND_DESKTOP, NULL);
    961         }
    962       }
    963 #ifdef DEBUG_BUILD
    964 //      printf("WM_MOUSEMOVE done\n"); fflush(stdout);
    965 #endif
    966 
    967       return (MRESULT) FALSE;
    968     case WM_CLOSE: // Window close
    969 #ifdef DEBUG_BUILD
    970       printf("WM_CLOSE\n"); fflush(stdout);
    971 #endif
    972 
    973       pVideo = FSLib_GetUserParm(hwnd);
    974       if (pVideo)
    975       {
    976         // Send Quit message to the SDL application!
    977         SDL_PrivateQuit();
    978         return 0;
    979       }
    980       break;
    981 
    982 #ifdef BITBLT_IN_WINMESSAGEPROC
    983     case WM_UPDATERECTSREQUEST:
    984       pVideo = FSLib_GetUserParm(hwnd);
    985       if ((pVideo) && (pVideo->hidden->pSDLSurface))
    986       {
    987         if (DosRequestMutexSem(pVideo->hidden->hmtxUseSrcBuffer, SEM_INDEFINITE_WAIT)==NO_ERROR)
    988         {
    989           int numrects;
    990           SDL_Rect *rects;
    991           int i;
    992           SWP swp;
    993 
    994           numrects = (int) mp1;
    995           rects = (SDL_Rect *) mp2;
    996 
    997           WinQueryWindowPos(hwnd, &swp);
    998 #ifndef RESIZE_EVEN_IF_RESIZABLE
    999           if ((!pVideo->hidden->pSDLSurface) ||
   1000               (
   1001                (pVideo->hidden->pSDLSurface) &&
   1002                (pVideo->hidden->pSDLSurface->flags & SDL_RESIZABLE) &&
   1003                ((swp.cx != pVideo->hidden->SrcBufferDesc.uiXResolution) ||
   1004                 (swp.cy != pVideo->hidden->SrcBufferDesc.uiYResolution)
   1005                ) &&
   1006                (!FSLib_QueryFSMode(hwnd))
   1007               )
   1008              )
   1009           {
   1010             // Resizable surface and in resizing!
   1011             // So, don't blit now!
   1012 #ifdef DEBUG_BUILD
   1013             printf("[WM_UPDATERECTSREQUEST] : Skipping blit while resizing!\n"); fflush(stdout);
   1014 #endif
   1015           } else
   1016 #endif
   1017           {
   1018 #ifdef DEBUG_BUILD
   1019             printf("[WM_UPDATERECTSREQUEST] : Blitting!\n"); fflush(stdout);
   1020 #endif
   1021 
   1022             // Blit the changed areas
   1023             for (i=0; i<numrects; i++)
   1024               FSLIB_BITBLT(hwnd, pVideo->hidden->pchSrcBuffer,
   1025                            rects[i].y, rects[i].x, rects[i].w, rects[i].h);
   1026           }
   1027           DosReleaseMutexSem(pVideo->hidden->hmtxUseSrcBuffer);
   1028         }
   1029       }
   1030       return 0;
   1031 #endif
   1032 
   1033     default:
   1034 #ifdef DEBUG_BUILD
   1035       printf("Unhandled: %x\n", msg); fflush(stdout);
   1036 #endif
   1037 
   1038       break;
   1039   }
   1040   // Run the default window procedure for unhandled stuffs
   1041   return WinDefWindowProc(hwnd, msg, mp1, mp2);
   1042 }
   1043 
   1044 /////////////////////////////////////////////////////////////////////
   1045 //
   1046 // FrameWndProc
   1047 //
   1048 // This is the message processing window procedure for the
   1049 // frame window of SDLWindowClass.
   1050 //
   1051 /////////////////////////////////////////////////////////////////////
   1052 static MRESULT EXPENTRY FrameWndProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
   1053 {
   1054   PFNWP pOldFrameProc;
   1055   MRESULT result;
   1056   PTRACKINFO ti;
   1057   int cx, cy, ncx, ncy;
   1058   RECTL rclTemp;
   1059   PSWP pswpTemp;
   1060 
   1061   SDL_VideoDevice *pVideo = NULL;
   1062 
   1063   pVideo = (SDL_VideoDevice *) WinQueryWindowULong(hwnd, QWL_USER);
   1064 
   1065   pOldFrameProc = pVideo->hidden->pfnOldFrameProc;
   1066 
   1067   if ((pVideo->hidden->bProportionalResize) &&
   1068       (msg==WM_ADJUSTWINDOWPOS) &&
   1069       (!FSLib_QueryFSMode(pVideo->hidden->hwndClient))
   1070      )
   1071   {
   1072     pswpTemp = (PSWP) mp1;
   1073 
   1074     /* Resizing? */
   1075     if (pswpTemp->fl & SWP_SIZE)
   1076     {
   1077       /* Calculate client size */
   1078       rclTemp.xLeft = pswpTemp->x;
   1079       rclTemp.xRight = pswpTemp->x + pswpTemp->cx;
   1080       rclTemp.yBottom = pswpTemp->y;
   1081       rclTemp.yTop = pswpTemp->y + pswpTemp->cy;
   1082       WinCalcFrameRect(hwnd, &rclTemp, TRUE);
   1083 
   1084       ncx = cx = rclTemp.xRight - rclTemp.xLeft;
   1085       ncy = cy = rclTemp.yTop - rclTemp.yBottom;
   1086 
   1087       /* Calculate new size to keep it proportional */
   1088 
   1089       if ((pVideo->hidden->ulResizingFlag & TF_LEFT) || (pVideo->hidden->ulResizingFlag & TF_RIGHT))
   1090       {
   1091         /* The window is resized horizontally */
   1092         ncy = pVideo->hidden->SrcBufferDesc.uiYResolution * cx / pVideo->hidden->SrcBufferDesc.uiXResolution;
   1093       } else
   1094       if ((pVideo->hidden->ulResizingFlag & TF_TOP) || (pVideo->hidden->ulResizingFlag & TF_BOTTOM))
   1095       {
   1096         /* The window is resized vertically */
   1097         ncx = pVideo->hidden->SrcBufferDesc.uiXResolution * cy / pVideo->hidden->SrcBufferDesc.uiYResolution;
   1098       }
   1099 
   1100       /* Calculate back frame coordinates */
   1101       rclTemp.xLeft = pswpTemp->x;
   1102       rclTemp.xRight = pswpTemp->x + ncx;
   1103       rclTemp.yBottom = pswpTemp->y;
   1104       rclTemp.yTop = pswpTemp->y + ncy;
   1105       WinCalcFrameRect(hwnd, &rclTemp, FALSE);
   1106 
   1107       /* Store new size/position info */
   1108       pswpTemp->cx = rclTemp.xRight - rclTemp.xLeft;
   1109 
   1110       if (!(pVideo->hidden->ulResizingFlag & TF_TOP))
   1111       {
   1112         pswpTemp->y = pswpTemp->y + pswpTemp->cy - (rclTemp.yTop - rclTemp.yBottom);
   1113         pswpTemp->cy = rclTemp.yTop - rclTemp.yBottom;
   1114       } else
   1115       {
   1116         pswpTemp->cy = rclTemp.yTop - rclTemp.yBottom;
   1117       }
   1118     }
   1119   }
   1120 
   1121   result = (*pOldFrameProc)(hwnd, msg, mp1, mp2);
   1122 
   1123   if ((pVideo->hidden->bProportionalResize) && (msg==WM_QUERYTRACKINFO))
   1124   {
   1125     ti = (PTRACKINFO) mp2;
   1126 
   1127     /* Store the direction of resizing */
   1128     if ((ti->fs & TF_LEFT) || (ti->fs & TF_RIGHT) ||
   1129         (ti->fs & TF_TOP) || (ti->fs & TF_BOTTOM))
   1130       pVideo->hidden->ulResizingFlag = ti->fs;
   1131   }
   1132 
   1133   return result;
   1134 }
   1135 
   1136 /////////////////////////////////////////////////////////////////////
   1137 //
   1138 // PMThreadFunc
   1139 //
   1140 // This function implements the PM-Thread, which initializes the
   1141 // application window itself, the DIVE, and start message processing.
   1142 //
   1143 /////////////////////////////////////////////////////////////////////
   1144 int iNumOfPMThreadInstances = 0; // Global!
   1145 static void PMThreadFunc(void *pParm)
   1146 {
   1147   SDL_VideoDevice *pVideo = pParm;
   1148   HAB hab;
   1149   HMQ hmq;
   1150   QMSG msg;
   1151   ULONG fcf;
   1152 
   1153 #ifdef DEBUG_BUILD
   1154   printf("[PMThreadFunc] : Starting\n"); fflush(stdout);
   1155 #endif
   1156 
   1157   iNumOfPMThreadInstances++;
   1158 
   1159   // Initialize PM, create a message queue.
   1160 
   1161   hab=WinInitialize(0);
   1162   hmq=WinCreateMsgQueue(hab,0);
   1163   if (hmq==0)
   1164   {
   1165 #ifdef DEBUG_BUILD
   1166     printf("[PMThreadFunc] : Could not create message queue!\n");
   1167     printf("                 It might be that the application using SDL is not a PM app!\n");
   1168     fflush(stdout);
   1169 #endif
   1170     pVideo->hidden->iPMThreadStatus = 2;
   1171   } else
   1172   {
   1173     int rc;
   1174     RECTL rectl;
   1175 
   1176     fcf = ulFCFToUse; // Get from global setting
   1177 
   1178 #ifdef DEBUG_BUILD
   1179     printf("[PMThreadFunc] : FSLib_CreateWindow()!\n");
   1180     fflush(stdout);
   1181 #endif
   1182 
   1183     rc = FSLib_CreateWindow(HWND_DESKTOP, 0, &fcf,
   1184                             "SDL Application",
   1185                             NULLHANDLE, 0,
   1186                             &(pVideo->hidden->SrcBufferDesc),
   1187                             WndProc,
   1188                             &(pVideo->hidden->hwndClient),
   1189                             &(pVideo->hidden->hwndFrame));
   1190 
   1191 #ifdef DEBUG_BUILD
   1192     printf("[PMThreadFunc] : FSLib_CreateWindow() rc = %d\n", rc);
   1193     fflush(stdout);
   1194 #endif
   1195 
   1196     if (!rc)
   1197     {
   1198 #ifdef DEBUG_BUILD
   1199       printf("[PMThreadFunc] : Could not create FSLib window!\n");
   1200       fflush(stdout);
   1201 #endif
   1202       pVideo->hidden->iPMThreadStatus = 3;
   1203     } else
   1204     {
   1205 #ifdef DEBUG_BUILD
   1206       printf("[PMThreadFunc] : FSLib_AddUserParm()!\n");
   1207       fflush(stdout);
   1208 #endif
   1209 
   1210       // Store pVideo pointer in window data for client window, so
   1211       // it will know the instance to which it belongs to.
   1212       FSLib_AddUserParm(pVideo->hidden->hwndClient, pVideo);
   1213 
   1214       // Now set default image width height and fourcc!
   1215 #ifdef DEBUG_BUILD
   1216       printf("[PMThreadFunc] : SetWindowPos()!\n");
   1217       fflush(stdout);
   1218 #endif
   1219 
   1220       // Set the position and size of the main window,
   1221       // and make it visible!
   1222       // Calculate frame window size from client window size
   1223       rectl.xLeft = 0;
   1224       rectl.yBottom = 0;
   1225       rectl.xRight = pVideo->hidden->SrcBufferDesc.uiXResolution; // Noninclusive
   1226       rectl.yTop = pVideo->hidden->SrcBufferDesc.uiYResolution; // Noninclusive
   1227       WinCalcFrameRect(pVideo->hidden->hwndFrame, &rectl, FALSE);
   1228 
   1229       SetAccessableWindowPos(pVideo->hidden->hwndFrame,
   1230                              HWND_TOP,
   1231                              (WinQuerySysValue (HWND_DESKTOP, SV_CXSCREEN) - (rectl.xRight-rectl.xLeft)) / 2,
   1232                              (WinQuerySysValue (HWND_DESKTOP, SV_CYSCREEN) - (rectl.yTop-rectl.yBottom)) / 2,
   1233                              (rectl.xRight-rectl.xLeft),
   1234                              (rectl.yTop-rectl.yBottom),
   1235                              SWP_SIZE | SWP_ACTIVATE | SWP_SHOW | SWP_MOVE);
   1236 
   1237       // Subclass frame procedure and store old window proc address
   1238       pVideo->hidden->pfnOldFrameProc =
   1239         WinSubclassWindow(pVideo->hidden->hwndFrame, FrameWndProc);
   1240       WinSetWindowULong(pVideo->hidden->hwndFrame, QWL_USER, (ULONG) pVideo);
   1241 
   1242 #ifdef DEBUG_BUILD
   1243       printf("[PMThreadFunc] : Entering message loop\n"); fflush(stdout);
   1244 #endif
   1245       pVideo->hidden->iPMThreadStatus = 1;
   1246 
   1247       while (WinGetMsg(hab, (PQMSG)&msg, 0, 0, 0))
   1248         WinDispatchMsg(hab, (PQMSG) &msg);
   1249 
   1250 #ifdef DEBUG_BUILD
   1251       printf("[PMThreadFunc] : Leaving message loop\n"); fflush(stdout);
   1252 #endif
   1253       // We should release the captured the mouse!
   1254       if (bMouseCaptured)
   1255       {
   1256         WinSetCapture(HWND_DESKTOP, NULLHANDLE);
   1257         bMouseCaptured = 0;
   1258       }
   1259       // Destroy our window
   1260       WinDestroyWindow(pVideo->hidden->hwndFrame); pVideo->hidden->hwndFrame=NULL;
   1261       // Show pointer to make sure it will not be left hidden.
   1262       WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE));
   1263       WinShowPointer(HWND_DESKTOP, TRUE);
   1264     }
   1265     // Uninitialize PM
   1266     WinDestroyMsgQueue(hmq);
   1267     // All done!
   1268     pVideo->hidden->iPMThreadStatus = 0;
   1269   }
   1270   WinTerminate(hab);
   1271   /* Commented out, should not be needed anymore, because we send it
   1272      from WM_CLOSE.
   1273   // Notify SDL that it should really die now...
   1274   SDL_PrivateQuit(); SDL_PrivateQuit(); SDL_PrivateQuit(); //... :))
   1275   */
   1276 #ifdef DEBUG_BUILD
   1277   printf("[PMThreadFunc] : End, status is %d!\n", pVideo->hidden->iPMThreadStatus); fflush(stdout);
   1278 #endif
   1279 
   1280   iNumOfPMThreadInstances--;
   1281 
   1282   // HACK to prevent zombie and hanging SDL applications, which does not take
   1283   // care of closing the window for some reason:
   1284   // There are some apps which do not process messages, so do a lot of things
   1285   // without noticing that the application should close. To close these,
   1286   // I've thought about the following:
   1287   // If the window is closed (the execution came here), I wait a bit to
   1288   // give time to the app to finish its execution. If it does not, I kill it
   1289   // using DosExit(). Brute force, but should work.
   1290   if (pVideo->hidden->iPMThreadStatus==0)
   1291   {
   1292     DosSleep(5000); // Wait 5 secs
   1293     // If a new PM thread has been spawned (reinitializing video mode), then all right.
   1294     // Otherwise, we have a problem, the app doesn't want to stop. Kill!
   1295     if (iNumOfPMThreadInstances==0)
   1296     {
   1297 #ifdef DEBUG_BUILD
   1298       printf("[PMThreadFunc] : It seems that the application haven't terminated itself\n"); fflush(stdout);
   1299       printf("[PMThreadFunc] : in the last 5 seconds, so we go berserk.\n"); fflush(stdout);
   1300       printf("[PMThreadFunc] : Brute force mode. :) Killing process! Dieeeee...\n"); fflush(stdout);
   1301 #endif
   1302       DosExit(EXIT_PROCESS, -1);
   1303     }
   1304   }
   1305   _endthread();
   1306 }
   1307 
   1308 struct WMcursor
   1309 {
   1310   HBITMAP hbm;
   1311   HPOINTER hptr;
   1312   char *pchData;
   1313 };
   1314 
   1315 /* Free a window manager cursor */
   1316 void os2fslib_FreeWMCursor(_THIS, WMcursor *cursor)
   1317 {
   1318   if (cursor)
   1319   {
   1320     GpiDeleteBitmap(cursor->hbm);
   1321     WinDestroyPointer(cursor->hptr);
   1322     SDL_free(cursor->pchData);
   1323     SDL_free(cursor);
   1324   }
   1325 }
   1326 
   1327 /* Local functions to convert the SDL cursor mask into OS/2 format */
   1328 static void memnot(Uint8 *dst, Uint8 *src, int len)
   1329 {
   1330   while ( len-- > 0 )
   1331     *dst++ = ~*src++;
   1332 }
   1333 static void memxor(Uint8 *dst, Uint8 *src1, Uint8 *src2, int len)
   1334 {
   1335   while ( len-- > 0 )
   1336     *dst++ = (*src1++)^(*src2++);
   1337 }
   1338 
   1339 /* Create a black/white window manager cursor */
   1340 WMcursor *os2fslib_CreateWMCursor_Win(_THIS, Uint8 *data, Uint8 *mask,
   1341                                       int w, int h, int hot_x, int hot_y)
   1342 {
   1343   HPOINTER hptr;
   1344   HBITMAP hbm;
   1345   BITMAPINFOHEADER bmih;
   1346   BMPINFO          bmi;
   1347   HPS              hps;
   1348   char *pchTemp;
   1349   char *xptr, *aptr;
   1350   int maxx, maxy;
   1351   int i, run, pad;
   1352   WMcursor *pResult;
   1353 
   1354   maxx = WinQuerySysValue(HWND_DESKTOP, SV_CXPOINTER);
   1355   maxy = WinQuerySysValue(HWND_DESKTOP, SV_CYPOINTER);
   1356 
   1357   // Check for max size!
   1358   if ((w>maxx) || (h>maxy))
   1359     return (WMcursor *) NULL;
   1360 
   1361   pResult = (WMcursor *) SDL_malloc(sizeof(WMcursor));
   1362   if (!pResult) return (WMcursor *) NULL;
   1363 
   1364   pchTemp = (char *) SDL_malloc((maxx + 7)/8 * maxy*2);
   1365   if (!pchTemp)
   1366   {
   1367     SDL_free(pResult);
   1368     return (WMcursor *) NULL;
   1369   }
   1370 
   1371   SDL_memset(pchTemp, 0, (maxx + 7)/8 * maxy*2);
   1372 
   1373   hps = WinGetPS(_this->hidden->hwndClient);
   1374 
   1375   bmi.cbFix = sizeof(BITMAPINFOHEADER);
   1376   bmi.cx = maxx;
   1377   bmi.cy = 2*maxy;
   1378   bmi.cPlanes = 1;
   1379   bmi.cBitCount = 1;
   1380   bmi.argbColor[0].bBlue = 0x00;
   1381   bmi.argbColor[0].bGreen = 0x00;
   1382   bmi.argbColor[0].bRed = 0x00;
   1383   bmi.argbColor[1].bBlue = 0x00;
   1384   bmi.argbColor[1].bGreen = 0x00;
   1385   bmi.argbColor[1].bRed = 0xff;
   1386 
   1387   SDL_memset(&bmih, 0, sizeof(BITMAPINFOHEADER));
   1388   bmih.cbFix = sizeof(BITMAPINFOHEADER);
   1389   bmih.cx = maxx;
   1390   bmih.cy = 2*maxy;
   1391   bmih.cPlanes = 1;
   1392   bmih.cBitCount = 1;
   1393 
   1394   run = (w+7)/8;
   1395   pad = (maxx+7)/8 - run;
   1396 
   1397   for (i=0; i<h; i++)
   1398   {
   1399     xptr = pchTemp + (maxx+7)/8 * (maxy-1-i);
   1400     aptr = pchTemp + (maxx+7)/8 * (maxy+maxy-1-i);
   1401     memxor(xptr, data, mask, run);
   1402     xptr += run;
   1403     data += run;
   1404     memnot(aptr, mask, run);
   1405     mask += run;
   1406     aptr += run;
   1407     SDL_memset(xptr,  0, pad);
   1408     xptr += pad;
   1409     SDL_memset(aptr, ~0, pad);
   1410     aptr += pad;
   1411   }
   1412   pad += run;
   1413   for (i=h ; i<maxy; i++ )
   1414   {
   1415     xptr = pchTemp + (maxx+7)/8 * (maxy-1-i);
   1416     aptr = pchTemp + (maxx+7)/8 * (maxy+maxy-1-i);
   1417 
   1418     SDL_memset(xptr,  0, (maxx+7)/8);
   1419     xptr += (maxx+7)/8;
   1420     SDL_memset(aptr, ~0, (maxx+7)/8);
   1421     aptr += (maxx+7)/8;
   1422   }
   1423 
   1424   hbm = GpiCreateBitmap(hps, (PBITMAPINFOHEADER2)&bmih, CBM_INIT, (PBYTE) pchTemp, (PBITMAPINFO2)&bmi);
   1425   hptr = WinCreatePointer(HWND_DESKTOP, hbm, TRUE, hot_x, maxy - hot_y - 1);
   1426 
   1427 #ifdef DEBUG_BUILD
   1428   printf("HotSpot          : %d ; %d\n", hot_x, hot_y);
   1429   printf("HPS returned     : %x\n", (ULONG)hps);
   1430   printf("HBITMAP returned : %x\n", (ULONG)hbm);
   1431   printf("HPOINTER returned: %x\n", (ULONG)hptr);
   1432 #endif
   1433 
   1434   WinReleasePS(hps);
   1435 
   1436 #ifdef DEBUG_BUILD
   1437   printf("[CreateWMCursor] : ptr = %p\n", hptr); fflush(stdout);
   1438 #endif
   1439 
   1440   pResult->hptr = hptr;
   1441   pResult->hbm = hbm;
   1442   pResult->pchData = pchTemp;
   1443 
   1444 #ifdef DEBUG_BUILD
   1445   printf("[CreateWMCursor] : ptr = %p return.\n", hptr); fflush(stdout);
   1446 #endif
   1447 
   1448   return (WMcursor *) pResult;
   1449 }
   1450 
   1451 WMcursor *os2fslib_CreateWMCursor_FS(_THIS, Uint8 *data, Uint8 *mask,
   1452                                      int w, int h, int hot_x, int hot_y)
   1453 {
   1454 #ifdef DEBUG_BUILD
   1455   printf("[CreateWMCursor_FS] : returning pointer NULL\n"); fflush(stdout);
   1456 #endif
   1457 
   1458   // In FS mode we'll use software cursor
   1459   return (WMcursor *) NULL;
   1460 }
   1461 
   1462 /* Show the specified cursor, or hide if cursor is NULL */
   1463 int os2fslib_ShowWMCursor(_THIS, WMcursor *cursor)
   1464 {
   1465 #ifdef DEBUG_BUILD
   1466   printf("[ShowWMCursor] : ptr = %p\n", cursor); fflush(stdout);
   1467 #endif
   1468 
   1469   if (cursor)
   1470   {
   1471     WinSetPointer(HWND_DESKTOP, cursor->hptr);
   1472     hptrGlobalPointer = cursor->hptr;
   1473     _this->hidden->iMouseVisible = 1;
   1474   }
   1475   else
   1476   {
   1477     WinSetPointer(HWND_DESKTOP, FALSE);
   1478     hptrGlobalPointer = NULL;
   1479     _this->hidden->iMouseVisible = 0;
   1480   }
   1481 
   1482 #ifdef DEBUG_BUILD
   1483   printf("[ShowWMCursor] : ptr = %p, DONE\n", cursor); fflush(stdout);
   1484 #endif
   1485 
   1486   return 1;
   1487 }
   1488 
   1489 /* Warp the window manager cursor to (x,y)
   1490  If NULL, a mouse motion event is posted internally.
   1491  */
   1492 void os2fslib_WarpWMCursor(_THIS, Uint16 x, Uint16 y)
   1493 {
   1494   LONG lx, ly;
   1495   SWP swpClient;
   1496   POINTL ptlPoints;
   1497   WinQueryWindowPos(_this->hidden->hwndClient, &swpClient);
   1498   ptlPoints.x = swpClient.x;
   1499   ptlPoints.y = swpClient.y;
   1500   WinMapWindowPoints(_this->hidden->hwndFrame, HWND_DESKTOP, &ptlPoints, 1);
   1501   lx = ptlPoints.x + (x*swpClient.cx) / _this->hidden->SrcBufferDesc.uiXResolution;
   1502   ly = ptlPoints.y + swpClient.cy - ((y*swpClient.cy) / _this->hidden->SrcBufferDesc.uiYResolution) - 1;
   1503 
   1504   SDL_PrivateMouseMotion(0, // Buttons not changed
   1505                          0, // Absolute position
   1506                          x,
   1507                          y);
   1508 
   1509   WinSetPointerPos(HWND_DESKTOP, lx, ly);
   1510 
   1511 }
   1512 
   1513 /* If not NULL, this is called when a mouse motion event occurs */
   1514 void os2fslib_MoveWMCursor(_THIS, int x, int y)
   1515 {
   1516   /*
   1517   SDL_Rect rect;
   1518 
   1519 #ifdef DEBUG_BUILD
   1520   printf("[MoveWMCursor] : at %d ; %d\n", x, y); fflush(stdout);
   1521 #endif
   1522 
   1523   rect.x = x;
   1524   rect.y = y;
   1525   rect.w = 32;
   1526   rect.h = 32;
   1527   os2fslib_UpdateRects(_this, 1, &rect);
   1528   // TODO!
   1529   */
   1530 }
   1531 
   1532 /* Determine whether the mouse should be in relative mode or not.
   1533  This function is called when the input grab state or cursor
   1534  visibility state changes.
   1535  If the cursor is not visible, and the input is grabbed, the
   1536  driver can place the mouse in relative mode, which may result
   1537  in higher accuracy sampling of the pointer motion.
   1538  */
   1539 void os2fslib_CheckMouseMode(_THIS)
   1540 {
   1541 }
   1542 
   1543 static void os2fslib_PumpEvents(_THIS)
   1544 {
   1545   // Notify SDL that if window has been resized!
   1546   if (
   1547       (_this->hidden->pSDLSurface) &&
   1548       (_this->hidden->pSDLSurface->flags & SDL_RESIZABLE) &&
   1549       (
   1550        (_this->hidden->SrcBufferDesc.uiXResolution!=iWindowSizeX) ||
   1551        (_this->hidden->SrcBufferDesc.uiYResolution!=iWindowSizeY)
   1552       ) &&
   1553       (iWindowSizeX>0) &&
   1554       (iWindowSizeY>0)
   1555      )
   1556   {
   1557     static time_t prev_time;
   1558     time_t curr_time;
   1559 
   1560     curr_time = time(NULL);
   1561     if ((difftime(curr_time, prev_time)>=0.25) ||
   1562         (bWindowResized))
   1563     {
   1564       // Make sure we won't flood the event queue with resize events,
   1565       // only send them at 250 msecs!
   1566       // (or when the window is resized)
   1567 #ifdef DEBUG_BUILD
   1568       printf("[os2fslib_PumpEvents] : Calling PrivateResize (%d %d).\n",
   1569              iWindowSizeX, iWindowSizeY);
   1570       fflush(stdout);
   1571 #endif
   1572       // Tell SDL the new size
   1573       SDL_PrivateResize(iWindowSizeX, iWindowSizeY);
   1574       prev_time = curr_time;
   1575       bWindowResized = 0;
   1576     }
   1577   }
   1578 }
   1579 
   1580 /* We don't actually allow hardware surfaces other than the main one */
   1581 static int os2fslib_AllocHWSurface(_THIS, SDL_Surface *surface)
   1582 {
   1583   return(-1);
   1584 }
   1585 static void os2fslib_FreeHWSurface(_THIS, SDL_Surface *surface)
   1586 {
   1587   return;
   1588 }
   1589 
   1590 /* We need to wait for vertical retrace on page flipped displays */
   1591 static int os2fslib_LockHWSurface(_THIS, SDL_Surface *surface)
   1592 {
   1593   return(0);
   1594 }
   1595 
   1596 static void os2fslib_UnlockHWSurface(_THIS, SDL_Surface *surface)
   1597 {
   1598   return;
   1599 }
   1600 
   1601 static int os2fslib_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
   1602 {
   1603   printf("[os2fslib_SetColors] : TODO!\n"); fflush(stdout);
   1604   // TODO: Implement paletted modes
   1605   return(1);
   1606 }
   1607 
   1608 static void os2fslib_DestroyIcon(HWND hwndFrame)
   1609 {
   1610   if (hptrCurrentIcon)
   1611   {
   1612     WinDestroyPointer(hptrCurrentIcon);
   1613     hptrCurrentIcon = NULL;
   1614 
   1615     WinSendMsg(hwndFrame,
   1616                WM_SETICON,
   1617                NULL,
   1618                NULL);
   1619   }
   1620 
   1621 }
   1622 
   1623 /* Set the window icon image */
   1624 void os2fslib_SetIcon(_THIS, SDL_Surface *icon, Uint8 *mask)
   1625 {
   1626   HWND hwndFrame;
   1627   SDL_Surface *icon_rgb;
   1628   HPOINTER hptrIcon;
   1629   HBITMAP hbm;
   1630   BITMAPINFOHEADER bmih;
   1631   BMPINFO          bmi;
   1632   HPS              hps;
   1633   char *pchTemp;
   1634   char *pptr, *mptr, *dptr, *dmptr;
   1635   int maxx, maxy, w, h, x, y;
   1636   SDL_Rect bounds;
   1637 
   1638 #ifdef DEBUG_BUILD
   1639   printf("[os2fslib_SetIcon] : Creating and setting new icon\n"); fflush(stdout);
   1640 #endif
   1641 
   1642   hwndFrame = WinQueryWindow(_this->hidden->hwndClient, QW_PARENT);
   1643 
   1644   // Make sure the old icon resource will be free'd!
   1645   os2fslib_DestroyIcon(hwndFrame);
   1646 
   1647   if ((!icon) || (!mask))
   1648     return;
   1649 
   1650   w = icon->w;
   1651   h = icon->h;
   1652 
   1653   maxx = WinQuerySysValue(HWND_DESKTOP, SV_CXICON);
   1654   maxy = WinQuerySysValue(HWND_DESKTOP, SV_CYICON);
   1655 
   1656   // Check for max size!
   1657   if ((w>maxx) || (h>maxy))
   1658     return;
   1659 
   1660   pchTemp = (char *) SDL_malloc(w * h*2 * 4);
   1661   if (!pchTemp)
   1662     return;
   1663 
   1664   SDL_memset(pchTemp, 0, w * h*2 * 4);
   1665 
   1666   // Convert surface to RGB, if it's not RGB yet!
   1667   icon_rgb = SDL_CreateRGBSurface(SDL_SWSURFACE, icon->w, icon->h,
   1668                                   32, 0, 0, 0, 0);
   1669   if ( icon_rgb == NULL )
   1670   {
   1671     SDL_free(pchTemp);
   1672     return;
   1673   }
   1674   bounds.x = 0;
   1675   bounds.y = 0;
   1676   bounds.w = icon->w;
   1677   bounds.h = icon->h;
   1678   if ( SDL_LowerBlit(icon, &bounds, icon_rgb, &bounds) < 0 )
   1679   {
   1680     SDL_FreeSurface(icon_rgb);
   1681     SDL_free(pchTemp);
   1682     return;
   1683   }
   1684 
   1685   /* Copy pixels upside-down from RGB surface into BMP, masked with the icon mask */
   1686 
   1687   // Pixels
   1688   pptr = (char *) (icon_rgb->pixels);
   1689   // Mask
   1690   mptr = mask;
   1691 
   1692   for (y=0; y<h; y++)
   1693   {
   1694     unsigned char uchMaskByte;
   1695 
   1696     // Destination
   1697     dptr = pchTemp + w*4 * (h-y-1);
   1698     // Destination mask
   1699     dmptr = pchTemp + w*h*4 + w*4 * (h-y-1);
   1700 
   1701     for (x=0; x<w; x++)
   1702     {
   1703       if (x%8==0)
   1704       {
   1705         uchMaskByte = (unsigned char) (*mptr);
   1706         mptr++;
   1707       } else
   1708         uchMaskByte <<= 1;
   1709 
   1710       if (uchMaskByte & 0x80)
   1711       {
   1712         // Copy RGB
   1713         *dptr++ = *pptr++;
   1714         *dptr++ = *pptr++;
   1715         *dptr++ = *pptr++;
   1716         *dptr++ = *pptr++;
   1717 
   1718         *dmptr++ = 0;
   1719         *dmptr++ = 0;
   1720         *dmptr++ = 0;
   1721         *dmptr++ = 0;
   1722       } else
   1723       {
   1724         // Set pixels to fully transparent
   1725         *dptr++ = 0; pptr++;
   1726         *dptr++ = 0; pptr++;
   1727         *dptr++ = 0; pptr++;
   1728         *dptr++ = 0; pptr++;
   1729 
   1730         *dmptr++ = 255;
   1731         *dmptr++ = 255;
   1732         *dmptr++ = 255;
   1733         *dmptr++ = 255;
   1734       }
   1735     }
   1736   }
   1737 
   1738   // There is no more need for the RGB surface
   1739   SDL_FreeSurface(icon_rgb);
   1740 
   1741   hps = WinGetPS(_this->hidden->hwndClient);
   1742 
   1743   bmi.cbFix = sizeof(BITMAPINFOHEADER);
   1744   bmi.cx = w;
   1745   bmi.cy = 2*h;
   1746   bmi.cPlanes = 1;
   1747   bmi.cBitCount = 32;
   1748 
   1749   SDL_memset(&bmih, 0, sizeof(BITMAPINFOHEADER));
   1750   bmih.cbFix = sizeof(BITMAPINFOHEADER);
   1751   bmih.cx = w;
   1752   bmih.cy = 2*h;
   1753   bmih.cPlanes = 1;
   1754   bmih.cBitCount = 32;
   1755 
   1756   hbm = GpiCreateBitmap(hps, (PBITMAPINFOHEADER2)&bmih, CBM_INIT, (PBYTE) pchTemp, (PBITMAPINFO2)&bmi);
   1757   hptrIcon = WinCreatePointer(HWND_DESKTOP, hbm, FALSE, 0, 0);
   1758 
   1759   WinReleasePS(hps);
   1760 
   1761   // Free pixel array
   1762   SDL_free(pchTemp);
   1763 
   1764   // Change icon in frame window
   1765   WinSendMsg(hwndFrame,
   1766              WM_SETICON,
   1767              (MPARAM) hptrIcon,
   1768              NULL);
   1769 
   1770   /*
   1771   // Change icon in switchlist
   1772   // Seems like it's not needed, the WM_SETICON already does it.
   1773   {
   1774     PID pidFrame;
   1775     HSWITCH hswitchFrame;
   1776     SWCNTRL swctl;
   1777 
   1778     WinQueryWindowProcess(hwndFrame, &pidFrame, NULL);
   1779     hswitchFrame = WinQuerySwitchHandle(hwndFrame, pidFrame);
   1780     WinQuerySwitchEntry(hswitchFrame, &swctl);
   1781 
   1782     swctl.hwndIcon = hptrIcon;
   1783 
   1784     WinChangeSwitchEntry(hswitchFrame, &swctl);
   1785   }
   1786   */
   1787 
   1788   // Store icon handle in global variable
   1789   hptrCurrentIcon = hptrIcon;
   1790 }
   1791 
   1792 // ------------------------ REAL FUNCTIONS -----------------
   1793 
   1794 
   1795 static void os2fslib_SetCursorManagementFunctions(_THIS, int iForWindowedMode)
   1796 {
   1797   if (iForWindowedMode)
   1798   {
   1799     _this->FreeWMCursor = os2fslib_FreeWMCursor;
   1800     _this->CreateWMCursor = os2fslib_CreateWMCursor_Win;
   1801     _this->ShowWMCursor = os2fslib_ShowWMCursor;
   1802     _this->WarpWMCursor = os2fslib_WarpWMCursor;
   1803     _this->MoveWMCursor = os2fslib_MoveWMCursor;
   1804     _this->CheckMouseMode = NULL;//os2fslib_CheckMouseMode;
   1805   } else
   1806   {
   1807     // We'll have software mouse cursor in FS mode!
   1808     _this->FreeWMCursor = os2fslib_FreeWMCursor;
   1809     _this->CreateWMCursor = os2fslib_CreateWMCursor_FS;
   1810     _this->ShowWMCursor = os2fslib_ShowWMCursor;
   1811     _this->WarpWMCursor = os2fslib_WarpWMCursor;
   1812     _this->MoveWMCursor = os2fslib_MoveWMCursor;
   1813     _this->CheckMouseMode = NULL;//os2fslib_CheckMouseMode;
   1814   }
   1815 }
   1816 
   1817 static void os2fslib_InitOSKeymap(_THIS)
   1818 {
   1819   int i;
   1820 
   1821   iShiftIsPressed = 0;
   1822 
   1823   /* Map the VK and CH keysyms */
   1824   for ( i=0; i<=255; ++i )
   1825     HWScanKeyMap[i] = SDLK_UNKNOWN;
   1826 
   1827   // First line of keyboard:
   1828   HWScanKeyMap[0x1] = SDLK_ESCAPE;
   1829   HWScanKeyMap[0x3b] = SDLK_F1;
   1830   HWScanKeyMap[0x3c] = SDLK_F2;
   1831   HWScanKeyMap[0x3d] = SDLK_F3;
   1832   HWScanKeyMap[0x3e] = SDLK_F4;
   1833   HWScanKeyMap[0x3f] = SDLK_F5;
   1834   HWScanKeyMap[0x40] = SDLK_F6;
   1835   HWScanKeyMap[0x41] = SDLK_F7;
   1836   HWScanKeyMap[0x42] = SDLK_F8;
   1837   HWScanKeyMap[0x43] = SDLK_F9;
   1838   HWScanKeyMap[0x44] = SDLK_F10;
   1839   HWScanKeyMap[0x57] = SDLK_F11;
   1840   HWScanKeyMap[0x58] = SDLK_F12;
   1841   HWScanKeyMap[0x5d] = SDLK_PRINT;
   1842   HWScanKeyMap[0x46] = SDLK_SCROLLOCK;
   1843   HWScanKeyMap[0x5f] = SDLK_PAUSE;
   1844 
   1845   // Second line of keyboard:
   1846   HWScanKeyMap[0x29] = SDLK_BACKQUOTE;
   1847   HWScanKeyMap[0x2] = SDLK_1;
   1848   HWScanKeyMap[0x3] = SDLK_2;
   1849   HWScanKeyMap[0x4] = SDLK_3;
   1850   HWScanKeyMap[0x5] = SDLK_4;
   1851   HWScanKeyMap[0x6] = SDLK_5;
   1852   HWScanKeyMap[0x7] = SDLK_6;
   1853   HWScanKeyMap[0x8] = SDLK_7;
   1854   HWScanKeyMap[0x9] = SDLK_8;
   1855   HWScanKeyMap[0xa] = SDLK_9;
   1856   HWScanKeyMap[0xb] = SDLK_0;
   1857   HWScanKeyMap[0xc] = SDLK_MINUS;
   1858   HWScanKeyMap[0xd] = SDLK_EQUALS;
   1859   HWScanKeyMap[0xe] = SDLK_BACKSPACE;
   1860   HWScanKeyMap[0x68] = SDLK_INSERT;
   1861   HWScanKeyMap[0x60] = SDLK_HOME;
   1862   HWScanKeyMap[0x62] = SDLK_PAGEUP;
   1863   HWScanKeyMap[0x45] = SDLK_NUMLOCK;
   1864   HWScanKeyMap[0x5c] = SDLK_KP_DIVIDE;
   1865   HWScanKeyMap[0x37] = SDLK_KP_MULTIPLY;
   1866   HWScanKeyMap[0x4a] = SDLK_KP_MINUS;
   1867 
   1868   // Third line of keyboard:
   1869   HWScanKeyMap[0xf] = SDLK_TAB;
   1870   HWScanKeyMap[0x10] = SDLK_q;
   1871   HWScanKeyMap[0x11] = SDLK_w;
   1872   HWScanKeyMap[0x12] = SDLK_e;
   1873   HWScanKeyMap[0x13] = SDLK_r;
   1874   HWScanKeyMap[0x14] = SDLK_t;
   1875   HWScanKeyMap[0x15] = SDLK_y;
   1876   HWScanKeyMap[0x16] = SDLK_u;
   1877   HWScanKeyMap[0x17] = SDLK_i;
   1878   HWScanKeyMap[0x18] = SDLK_o;
   1879   HWScanKeyMap[0x19] = SDLK_p;
   1880   HWScanKeyMap[0x1a] = SDLK_LEFTBRACKET;
   1881   HWScanKeyMap[0x1b] = SDLK_RIGHTBRACKET;
   1882   HWScanKeyMap[0x1c] = SDLK_RETURN;
   1883   HWScanKeyMap[0x69] = SDLK_DELETE;
   1884   HWScanKeyMap[0x65] = SDLK_END;
   1885   HWScanKeyMap[0x67] = SDLK_PAGEDOWN;
   1886   HWScanKeyMap[0x47] = SDLK_KP7;
   1887   HWScanKeyMap[0x48] = SDLK_KP8;
   1888   HWScanKeyMap[0x49] = SDLK_KP9;
   1889   HWScanKeyMap[0x4e] = SDLK_KP_PLUS;
   1890 
   1891   // Fourth line of keyboard:
   1892   HWScanKeyMap[0x3a] = SDLK_CAPSLOCK;
   1893   HWScanKeyMap[0x1e] = SDLK_a;
   1894   HWScanKeyMap[0x1f] = SDLK_s;
   1895   HWScanKeyMap[0x20] = SDLK_d;
   1896   HWScanKeyMap[0x21] = SDLK_f;
   1897   HWScanKeyMap[0x22] = SDLK_g;
   1898   HWScanKeyMap[0x23] = SDLK_h;
   1899   HWScanKeyMap[0x24] = SDLK_j;
   1900   HWScanKeyMap[0x25] = SDLK_k;
   1901   HWScanKeyMap[0x26] = SDLK_l;
   1902   HWScanKeyMap[0x27] = SDLK_SEMICOLON;
   1903   HWScanKeyMap[0x28] = SDLK_QUOTE;
   1904   HWScanKeyMap[0x2b] = SDLK_BACKSLASH;
   1905   HWScanKeyMap[0x4b] = SDLK_KP4;
   1906   HWScanKeyMap[0x4c] = SDLK_KP5;
   1907   HWScanKeyMap[0x4d] = SDLK_KP6;
   1908 
   1909   // Fifth line of keyboard:
   1910   HWScanKeyMap[0x2a] = SDLK_LSHIFT;
   1911   HWScanKeyMap[0x56] = SDLK_WORLD_1; // Code 161, letter i' on hungarian keyboard
   1912   HWScanKeyMap[0x2c] = SDLK_z;
   1913   HWScanKeyMap[0x2d] = SDLK_x;
   1914   HWScanKeyMap[0x2e] = SDLK_c;
   1915   HWScanKeyMap[0x2f] = SDLK_v;
   1916   HWScanKeyMap[0x30] = SDLK_b;
   1917   HWScanKeyMap[0x31] = SDLK_n;
   1918   HWScanKeyMap[0x32] = SDLK_m;
   1919   HWScanKeyMap[0x33] = SDLK_COMMA;
   1920   HWScanKeyMap[0x34] = SDLK_PERIOD;
   1921   HWScanKeyMap[0x35] = SDLK_SLASH;
   1922   HWScanKeyMap[0x36] = SDLK_RSHIFT;
   1923   HWScanKeyMap[0x61] = SDLK_UP;
   1924   HWScanKeyMap[0x4f] = SDLK_KP1;
   1925   HWScanKeyMap[0x50] = SDLK_KP2;
   1926   HWScanKeyMap[0x51] = SDLK_KP3;
   1927   HWScanKeyMap[0x5a] = SDLK_KP_ENTER;
   1928 
   1929   // Sixth line of keyboard:
   1930   HWScanKeyMap[0x1d] = SDLK_LCTRL;
   1931   HWScanKeyMap[0x7e] = SDLK_LSUPER; // Windows key
   1932   HWScanKeyMap[0x38] = SDLK_LALT;
   1933   HWScanKeyMap[0x39] = SDLK_SPACE;
   1934   HWScanKeyMap[0x5e] = SDLK_RALT;// Actually, altgr on my keyboard...
   1935   HWScanKeyMap[0x7f] = SDLK_RSUPER;
   1936   HWScanKeyMap[0x7c] = SDLK_MENU;
   1937   HWScanKeyMap[0x5b] = SDLK_RCTRL;
   1938   HWScanKeyMap[0x63] = SDLK_LEFT;
   1939   HWScanKeyMap[0x66] = SDLK_DOWN;
   1940   HWScanKeyMap[0x64] = SDLK_RIGHT;
   1941   HWScanKeyMap[0x52] = SDLK_KP0;
   1942   HWScanKeyMap[0x53] = SDLK_KP_PERIOD;
   1943 }
   1944 
   1945 
   1946 /* Iconify the window.
   1947  This function returns 1 if there is a window manager and the
   1948  window was actually iconified, it returns 0 otherwise.
   1949  */
   1950 int os2fslib_IconifyWindow(_THIS)
   1951 {
   1952   HAB hab;
   1953   HMQ hmq;
   1954   ERRORID hmqerror;
   1955 
   1956   // If there is no more window, nothing we can do!
   1957   if (_this->hidden->iPMThreadStatus!=1) return 0;
   1958 
   1959   // Cannot do anything in fullscreen mode!
   1960   if (FSLib_QueryFSMode(_this->hidden->hwndClient))
   1961     return 0;
   1962 
   1963   // Make sure this thread is prepared for using the Presentation Manager!
   1964   hab = WinInitialize(0);
   1965   hmq = WinCreateMsgQueue(hab,0);
   1966   // Remember if there was an error at WinCreateMsgQueue(), because we don't
   1967   // want to destroy somebody else's queue later. :)
   1968   hmqerror = WinGetLastError(hab);
   1969 
   1970   WinSetWindowPos(_this->hidden->hwndFrame, HWND_TOP,
   1971                  0, 0, 0, 0, SWP_MINIMIZE);
   1972 
   1973   // Now destroy the message queue, if we've created it!
   1974   if (ERRORIDERROR(hmqerror)==0)
   1975     WinDestroyMsgQueue(hmq);
   1976 
   1977   return 1;
   1978 }
   1979 
   1980 static SDL_GrabMode os2fslib_GrabInput(_THIS, SDL_GrabMode mode)
   1981 {
   1982   HAB hab;
   1983   HMQ hmq;
   1984   ERRORID hmqerror;
   1985 
   1986 
   1987   // If there is no more window, nothing we can do!
   1988   if (_this->hidden->iPMThreadStatus!=1)
   1989     return SDL_GRAB_OFF;
   1990 
   1991   // Make sure this thread is prepared for using the Presentation Manager!
   1992   hab = WinInitialize(0);
   1993   hmq = WinCreateMsgQueue(hab,0);
   1994   // Remember if there was an error at WinCreateMsgQueue(), because we don't
   1995   // want to destroy somebody else's queue later. :)
   1996   hmqerror = WinGetLastError(hab);
   1997 
   1998 
   1999   if (mode == SDL_GRAB_OFF)
   2000   {
   2001 #ifdef DEBUG_BUILD
   2002     printf("[os2fslib_GrabInput] : Releasing mouse\n"); fflush(stdout);
   2003 #endif
   2004 
   2005     // Release the mouse
   2006     bMouseCapturable = 0;
   2007     if (bMouseCaptured)
   2008     {
   2009       WinSetCapture(HWND_DESKTOP, NULLHANDLE);
   2010       bMouseCaptured = 0;
   2011     }
   2012   } else
   2013   {
   2014 #ifdef DEBUG_BUILD
   2015     printf("[os2fslib_GrabInput] : Capturing mouse\n"); fflush(stdout);
   2016 #endif
   2017 
   2018     // Capture the mouse
   2019     bMouseCapturable = 1;
   2020     if (WinQueryFocus(HWND_DESKTOP) == _this->hidden->hwndClient)
   2021     {
   2022       WinSetCapture(HWND_DESKTOP, _this->hidden->hwndClient);
   2023       bMouseCaptured = 1;
   2024       {
   2025         SWP swpClient;
   2026         POINTL ptl;
   2027         // Center the mouse to the middle of the window!
   2028         WinQueryWindowPos(_this->hidden->hwndClient, &swpClient);
   2029         ptl.x = 0; ptl.y = 0;
   2030         WinMapWindowPoints(_this->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
   2031         _this->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account!  */
   2032         WinSetPointerPos(HWND_DESKTOP,
   2033                          ptl.x + swpClient.cx/2,
   2034                          ptl.y + swpClient.cy/2);
   2035       }
   2036     }
   2037   }
   2038 
   2039   // Now destroy the message queue, if we've created it!
   2040   if (ERRORIDERROR(hmqerror)==0)
   2041     WinDestroyMsgQueue(hmq);
   2042 
   2043   return mode;
   2044 }
   2045 
   2046 /* Set the title and icon text */
   2047 static void os2fslib_SetCaption(_THIS, const char *title, const char *icon)
   2048 {
   2049   HAB hab;
   2050   HMQ hmq;
   2051   ERRORID hmqerror;
   2052 
   2053   // If there is no more window, nothing we can do!
   2054   if (_this->hidden->iPMThreadStatus!=1) return;
   2055 
   2056   // Make sure this thread is prepared for using the Presentation Manager!
   2057   hab = WinInitialize(0);
   2058   hmq = WinCreateMsgQueue(hab,0);
   2059   // Remember if there was an error at WinCreateMsgQueue(), because we don't
   2060   // want to destroy somebody else's queue later. :)
   2061   hmqerror = WinGetLastError(hab);
   2062 
   2063   WinSetWindowText(_this->hidden->hwndFrame, (char *) title);
   2064 
   2065   // Now destroy the message queue, if we've created it!
   2066   if (ERRORIDERROR(hmqerror)==0)
   2067     WinDestroyMsgQueue(hmq);
   2068 }
   2069 
   2070 static int os2fslib_ToggleFullScreen(_THIS, int on)
   2071 {
   2072 #ifdef DEBUG_BUILD
   2073   printf("[os2fslib_ToggleFullScreen] : %d\n", on); fflush(stdout);
   2074 #endif
   2075   // If there is no more window, nothing we can do!
   2076   if (_this->hidden->iPMThreadStatus!=1) return 0;
   2077 
   2078   FSLib_ToggleFSMode(_this->hidden->hwndClient, on);
   2079   /* Cursor manager functions to Windowed/FS mode*/
   2080   os2fslib_SetCursorManagementFunctions(_this, !on);
   2081   return 1;
   2082 }
   2083 
   2084 /* This is called after the video mode has been set, to get the
   2085  initial mouse state.  It should queue events as necessary to
   2086  properly represent the current mouse focus and position.
   2087  */
   2088 static void os2fslib_UpdateMouse(_THIS)
   2089 {
   2090   POINTL ptl;
   2091   HAB hab;
   2092   HMQ hmq;
   2093   ERRORID hmqerror;
   2094   SWP swpClient;
   2095 
   2096   // If there is no more window, nothing we can do!
   2097   if (_this->hidden->iPMThreadStatus!=1) return;
   2098 
   2099 
   2100   // Make sure this thread is prepared for using the Presentation Manager!
   2101   hab = WinInitialize(0);
   2102   hmq = WinCreateMsgQueue(hab,0);
   2103   // Remember if there was an error at WinCreateMsgQueue(), because we don't
   2104   // want to destroy somebody else's queue later. :)
   2105   hmqerror = WinGetLastError(hab);
   2106 
   2107 
   2108 
   2109   if (_this->hidden->fInFocus)
   2110   {
   2111     // If our app is in focus
   2112     SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
   2113     SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS);
   2114     SDL_PrivateAppActive(1, SDL_APPACTIVE);
   2115     WinQueryPointerPos(HWND_DESKTOP, &ptl);
   2116     WinMapWindowPoints(HWND_DESKTOP, _this->hidden->hwndClient, &ptl, 1);
   2117     WinQueryWindowPos(_this->hidden->hwndClient, &swpClient);
   2118     // Convert OS/2 mouse position to SDL position, and also scale it!
   2119     ptl.x = ptl.x * _this->hidden->SrcBufferDesc.uiXResolution / swpClient.cx;
   2120     ptl.y = ptl.y * _this->hidden->SrcBufferDesc.uiYResolution / swpClient.cy;
   2121     ptl.y = _this->hidden->SrcBufferDesc.uiYResolution - ptl.y - 1;
   2122     SDL_PrivateMouseMotion(0, 0, (Sint16) (ptl.x), (Sint16) (ptl.y));
   2123   } else
   2124   {
   2125     // If we're not in focus
   2126     SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
   2127     SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS);
   2128     SDL_PrivateAppActive(0, SDL_APPACTIVE);
   2129     SDL_PrivateMouseMotion(0, 0, (Sint16) -1, (Sint16) -1);
   2130   }
   2131 
   2132   // Now destroy the message queue, if we've created it!
   2133   if (ERRORIDERROR(hmqerror)==0)
   2134     WinDestroyMsgQueue(hmq);
   2135 
   2136 }
   2137 
   2138 /* This pointer should exist in the native video subsystem and should
   2139  point to an appropriate update function for the current video mode
   2140  */
   2141 static void os2fslib_UpdateRects(_THIS, int numrects, SDL_Rect *rects)
   2142 {
   2143   // If there is no more window, nothing we can do!
   2144   if (_this->hidden->iPMThreadStatus!=1) return;
   2145 
   2146 #ifdef BITBLT_IN_WINMESSAGEPROC
   2147   WinSendMsg(_this->hidden->hwndClient,
   2148                  WM_UPDATERECTSREQUEST,
   2149                  (MPARAM) numrects,
   2150                  (MPARAM) rects);
   2151 #else
   2152   if (DosRequestMutexSem(_this->hidden->hmtxUseSrcBuffer, SEM_INDEFINITE_WAIT)==NO_ERROR)
   2153   {
   2154     int i;
   2155 
   2156     if (_this->hidden->pSDLSurface)
   2157     {
   2158 #ifndef RESIZE_EVEN_IF_RESIZABLE
   2159       SWP swp;
   2160       // But only blit if the window is not resizable, or if
   2161       // the window is resizable and the source buffer size is the
   2162       // same as the destination buffer size!
   2163       WinQueryWindowPos(_this->hidden->hwndClient, &swp);
   2164       if ((_this->hidden->pSDLSurface) &&
   2165           (_this->hidden->pSDLSurface->flags & SDL_RESIZABLE) &&
   2166           ((swp.cx != _this->hidden->SrcBufferDesc.uiXResolution) ||
   2167            (swp.cy != _this->hidden->SrcBufferDesc.uiYResolution)
   2168           ) &&
   2169           (!FSLib_QueryFSMode(_this->hidden->hwndClient))
   2170          )
   2171       {
   2172         // Resizable surface and in resizing!
   2173         // So, don't blit now!
   2174 #ifdef DEBUG_BUILD
   2175         printf("[UpdateRects] : Skipping blit while resizing!\n"); fflush(stdout);
   2176 #endif
   2177       } else
   2178 #endif
   2179       {
   2180       /*
   2181         // Blit the whole window
   2182         FSLIB_BITBLT(_this->hidden->hwndClient, _this->hidden->pchSrcBuffer,
   2183                      0, 0,
   2184                      _this->hidden->SrcBufferDesc.uiXResolution,
   2185                      _this->hidden->SrcBufferDesc.uiYResolution);
   2186                      */
   2187 #ifdef DEBUG_BUILD
   2188           printf("[os2fslib_UpdateRects] : Blitting!\n"); fflush(stdout);
   2189 #endif
   2190 
   2191         // Blit the changed areas
   2192         for (i=0; i<numrects; i++)
   2193           FSLIB_BITBLT(_this->hidden->hwndClient, _this->hidden->pchSrcBuffer,
   2194                        rects[i].y, rects[i].x, rects[i].w, rects[i].h);
   2195       }
   2196     }
   2197 #ifdef DEBUG_BUILD
   2198      else
   2199        printf("[os2fslib_UpdateRects] : No public surface!\n"); fflush(stdout);
   2200 #endif
   2201     DosReleaseMutexSem(_this->hidden->hmtxUseSrcBuffer);
   2202   }
   2203 #ifdef DEBUG_BUILD
   2204   else
   2205     printf("[os2fslib_UpdateRects] : Error in mutex!\n"); fflush(stdout);
   2206 #endif
   2207 #endif
   2208 }
   2209 
   2210 
   2211 /* Reverse the effects VideoInit() -- called if VideoInit() fails
   2212  or if the application is shutting down the video subsystem.
   2213  */
   2214 static void os2fslib_VideoQuit(_THIS)
   2215 {
   2216 #ifdef DEBUG_BUILD
   2217   printf("[os2fslib_VideoQuit]\n"); fflush(stdout);
   2218 #endif
   2219   // Close PM stuff if running!
   2220   if (_this->hidden->iPMThreadStatus == 1)
   2221   {
   2222     int iTimeout;
   2223     WinPostMsg(_this->hidden->hwndFrame, WM_QUIT, (MPARAM) 0, (MPARAM) 0);
   2224     // HACK: We had this line before:
   2225     //DosWaitThread((TID *) &(_this->hidden->tidPMThread), DCWW_WAIT);
   2226     // We don't use it, because the PMThread will never stop, or if it stops,
   2227     // it will kill the whole process as a emergency fallback.
   2228     // So, we only check for the iPMThreadStatus stuff!
   2229 #ifdef DEBUG_BUILD
   2230     printf("[os2fslib_VideoQuit] : Waiting for PM thread to die\n"); fflush(stdout);
   2231 #endif
   2232 
   2233     iTimeout=0;
   2234     while ((_this->hidden->iPMThreadStatus == 1) && (iTimeout<100))
   2235     {
   2236       iTimeout++;
   2237       DosSleep(64);
   2238     }
   2239 
   2240 #ifdef DEBUG_BUILD
   2241     printf("[os2fslib_VideoQuit] : End of wait.\n"); fflush(stdout);
   2242 #endif
   2243 
   2244     if (_this->hidden->iPMThreadStatus == 1)
   2245     {
   2246 #ifdef DEBUG_BUILD
   2247       printf("[os2fslib_VideoQuit] : Killing PM thread!\n"); fflush(stdout);
   2248 #endif
   2249 
   2250       _this->hidden->iPMThreadStatus = 0;
   2251       DosKillThread(_this->hidden->tidPMThread);
   2252 
   2253       if (_this->hidden->hwndFrame)
   2254       {
   2255 #ifdef DEBUG_BUILD
   2256         printf("[os2fslib_VideoQuit] : Destroying PM window!\n"); fflush(stdout);
   2257 #endif
   2258 
   2259         WinDestroyWindow(_this->hidden->hwndFrame); _this->hidden->hwndFrame=NULL;
   2260       }
   2261     }
   2262 
   2263   }
   2264 
   2265   // Free result of an old ListModes() call, because there is
   2266   // no FreeListModes() call in SDL!
   2267   if (_this->hidden->pListModesResult)
   2268   {
   2269     SDL_free(_this->hidden->pListModesResult); _this->hidden->pListModesResult = NULL;
   2270   }
   2271 
   2272   // Free list of available fullscreen modes
   2273   if (_this->hidden->pAvailableFSLibVideoModes)
   2274   {
   2275     FSLib_FreeVideoModeList(_this->hidden->pAvailableFSLibVideoModes);
   2276     _this->hidden->pAvailableFSLibVideoModes = NULL;
   2277   }
   2278 
   2279   // Free application icon if we had one
   2280   if (hptrCurrentIcon)
   2281   {
   2282     WinDestroyPointer(hptrCurrentIcon);
   2283     hptrCurrentIcon = NULL;
   2284   }
   2285 }
   2286 
   2287 /* Set the requested video mode, returning a surface which will be
   2288  set to the SDL_VideoSurface.  The width and height will already
   2289  be verified by ListModes(), and the video subsystem is free to
   2290  set the mode to a supported bit depth different from the one
   2291  specified -- the desired bpp will be emulated with a shadow
   2292  surface if necessary.  If a new mode is returned, this function
   2293  should take care of cleaning up the current mode.
   2294  */
   2295 static SDL_Surface *os2fslib_SetVideoMode(_THIS, SDL_Surface *current,
   2296                                           int width, int height, int bpp, Uint32 flags)
   2297 {
   2298   static int bFirstCall = 1;
   2299   FSLib_VideoMode_p pModeInfo, pModeInfoFound;
   2300   FSLib_VideoMode TempModeInfo;
   2301   HAB hab;
   2302   HMQ hmq;
   2303   ERRORID hmqerror;
   2304   RECTL rectl;
   2305   SDL_Surface *pResult;
   2306 
   2307   // If there is no more window, nothing we can do!
   2308   if (_this->hidden->iPMThreadStatus!=1) return NULL;
   2309 
   2310 #ifdef DEBUG_BUILD
   2311   printf("[os2fslib_SetVideoMode] : Request for %dx%d @ %dBPP, flags=0x%x\n", width, height, bpp, flags); fflush(stdout);
   2312 #endif
   2313 
   2314   // We don't support palette modes!
   2315   if (bpp==8) bpp=32;
   2316 
   2317   // Also, we don't support resizable modes in fullscreen mode.
   2318   if (flags & SDL_RESIZABLE)
   2319     flags &= ~SDL_FULLSCREEN;
   2320 
   2321   // No double buffered mode
   2322   if (flags & SDL_DOUBLEBUF)
   2323     flags &= ~SDL_DOUBLEBUF;
   2324 
   2325   // And, we don't support HWSURFACE yet.
   2326   if (flags & SDL_HWSURFACE)
   2327   {
   2328     flags &= ~SDL_HWSURFACE;
   2329     flags |= SDL_SWSURFACE;
   2330   }
   2331 
   2332 #ifdef DEBUG_BUILD
   2333   printf("[os2fslib_SetVideoMode] : Changed request to %dx%d @ %dBPP, flags=0x%x\n", width, height, bpp, flags); fflush(stdout);
   2334 #endif
   2335 
   2336   // First check if there is such a video mode they want!
   2337   pModeInfoFound = NULL;
   2338 
   2339   // For fullscreen mode we don't support every resolution!
   2340   // So, go through the video modes, and check for such a resolution!
   2341   pModeInfoFound = NULL;
   2342   pModeInfo = _this->hidden->pAvailableFSLibVideoModes;
   2343 
   2344   while (pModeInfo)
   2345   {
   2346     // Check all available fullscreen modes for this resolution
   2347     if ((pModeInfo->uiXResolution == width) &&
   2348         (pModeInfo->uiYResolution == height) &&
   2349         (pModeInfo->uiBPP!=8)) // palettized modes not yet supported
   2350     {
   2351       // If good resolution, try to find the exact BPP, or at least
   2352       // something similar...
   2353       if (!pModeInfoFound)
   2354         pModeInfoFound = pModeInfo;
   2355       else
   2356       if ((pModeInfoFound->uiBPP!=bpp) &&
   2357           (pModeInfoFound->uiBPP<pModeInfo->uiBPP))
   2358         pModeInfoFound = pModeInfo;
   2359     }
   2360     pModeInfo = pModeInfo->pNext;
   2361   }
   2362 
   2363   // If we did not find a good fullscreen mode, then try a similar
   2364   if (!pModeInfoFound)
   2365   {
   2366 #ifdef DEBUG_BUILD
   2367     printf("[os2fslib_SetVideoMode] : Requested video mode not found, looking for a similar one!\n"); fflush(stdout);
   2368 #endif
   2369     // Go through the video modes again, and find a similar resolution!
   2370     pModeInfo = _this->hidden->pAvailableFSLibVideoModes;
   2371     while (pModeInfo)
   2372     {
   2373       // Check all available fullscreen modes for this resolution
   2374       if ((pModeInfo->uiXResolution >= width) &&
   2375           (pModeInfo->uiYResolution >= height) &&
   2376           (pModeInfo->uiBPP == bpp))
   2377       {
   2378         if (!pModeInfoFound)
   2379           pModeInfoFound = pModeInfo;
   2380         else
   2381         if (((pModeInfoFound->uiXResolution-width)*(pModeInfoFound->uiYResolution-height))>
   2382             ((pModeInfo->uiXResolution-width)*(pModeInfo->uiYResolution-height)))
   2383         {
   2384           // Found a mode which is closer than the current one
   2385           pModeInfoFound = pModeInfo;
   2386         }
   2387       }
   2388       pModeInfo = pModeInfo->pNext;
   2389     }
   2390   }
   2391 
   2392   // If we did not find a good fullscreen mode, then return NULL
   2393   if (!pModeInfoFound)
   2394   {
   2395 #ifdef DEBUG_BUILD
   2396     printf("[os2fslib_SetVideoMode] : Requested video mode not found!\n"); fflush(stdout);
   2397 #endif
   2398     return NULL;
   2399   }
   2400 
   2401 #ifdef DEBUG_BUILD
   2402   printf("[os2fslib_SetVideoMode] : Found mode!\n"); fflush(stdout);
   2403 #endif
   2404 
   2405   // We'll possibly adjust the structure, so copy out the values
   2406   // into TempModeInfo!
   2407   SDL_memcpy(&TempModeInfo, pModeInfoFound, sizeof(TempModeInfo));
   2408   pModeInfoFound = &TempModeInfo;
   2409 
   2410   if (flags & SDL_RESIZABLE)
   2411   {
   2412 #ifdef DEBUG_BUILD
   2413     printf("[os2fslib_SetVideoMode] : Requested mode is resizable, changing width/height\n"); fflush(stdout);
   2414 #endif
   2415     // Change width and height to requested one!
   2416     TempModeInfo.uiXResolution = width;
   2417     TempModeInfo.uiYResolution = height;
   2418     TempModeInfo.uiScanLineSize = width * ((TempModeInfo.uiBPP+7)/8);
   2419   }
   2420 
   2421   // We can try create new surface!
   2422 
   2423   // Make sure this thread is prepared for using the Presentation Manager!
   2424   hab = WinInitialize(0);
   2425   hmq = WinCreateMsgQueue(hab,0);
   2426   // Remember if there was an error at WinCreateMsgQueue(), because we don't
   2427   // want to destroy somebody else's queue later. :)
   2428   hmqerror = WinGetLastError(hab);
   2429 
   2430 
   2431 
   2432   if (DosRequestMutexSem(_this->hidden->hmtxUseSrcBuffer, SEM_INDEFINITE_WAIT)==NO_ERROR)
   2433   {
   2434 #ifdef DEBUG_BUILD
   2435     printf("[os2fslib_SetVideoMode] : Creating new SW surface\n"); fflush(stdout);
   2436 #endif
   2437 
   2438     // Create new software surface!
   2439     pResult = SDL_CreateRGBSurface(SDL_SWSURFACE,
   2440                                    pModeInfoFound->uiXResolution,
   2441                                    pModeInfoFound->uiYResolution,
   2442                                    pModeInfoFound->uiBPP,
   2443                                    ((unsigned int) pModeInfoFound->PixelFormat.ucRedMask) << pModeInfoFound->PixelFormat.ucRedPosition,
   2444                                    ((unsigned int) pModeInfoFound->PixelFormat.ucGreenMask) << pModeInfoFound->PixelFormat.ucGreenPosition,
   2445                                    ((unsigned int) pModeInfoFound->PixelFormat.ucBlueMask) << pModeInfoFound->PixelFormat.ucBluePosition,
   2446                                    ((unsigned int) pModeInfoFound->PixelFormat.ucAlphaMask) << pModeInfoFound->PixelFormat.ucAlphaPosition);
   2447 
   2448     if (pResult == NULL)
   2449     {
   2450       DosReleaseMutexSem(_this->hidden->hmtxUseSrcBuffer);
   2451       SDL_OutOfMemory();
   2452       return NULL;
   2453     }
   2454 
   2455 #ifdef DEBUG_BUILD
   2456     printf("[os2fslib_SetVideoMode] : Adjusting pixel format\n"); fflush(stdout);
   2457 #endif
   2458 
   2459     // Adjust pixel format mask!
   2460     pResult->format->Rmask = ((unsigned int) pModeInfoFound->PixelFormat.ucRedMask) << pModeInfoFound->PixelFormat.ucRedPosition;
   2461     pResult->format->Rshift = pModeInfoFound->PixelFormat.ucRedPosition;
   2462     pResult->format->Rloss = pModeInfoFound->PixelFormat.ucRedAdjust;
   2463     pResult->format->Gmask = ((unsigned int) pModeInfoFound->PixelFormat.ucGreenMask) << pModeInfoFound->PixelFormat.ucGreenPosition;
   2464     pResult->format->Gshift = pModeInfoFound->PixelFormat.ucGreenPosition;
   2465     pResult->format->Gloss = pModeInfoFound->PixelFormat.ucGreenAdjust;
   2466     pResult->format->Bmask = ((unsigned int) pModeInfoFound->PixelFormat.ucBlueMask) << pModeInfoFound->PixelFormat.ucBluePosition;
   2467     pResult->format->Bshift = pModeInfoFound->PixelFormat.ucBluePosition;
   2468     pResult->format->Bloss = pModeInfoFound->PixelFormat.ucBlueAdjust;
   2469     pResult->format->Amask = ((unsigned int) pModeInfoFound->PixelFormat.ucAlphaMask) << pModeInfoFound->PixelFormat.ucAlphaPosition;
   2470     pResult->format->Ashift = pModeInfoFound->PixelFormat.ucAlphaPosition;
   2471     pResult->format->Aloss = pModeInfoFound->PixelFormat.ucAlphaAdjust;
   2472 
   2473 #ifdef REPORT_EMPTY_ALPHA_MASK
   2474     pResult->format->Amask =
   2475         pResult->format->Ashift =
   2476         pResult->format->Aloss = 0;
   2477 #endif
   2478 
   2479     // Adjust surface flags
   2480     pResult->flags |= (flags & SDL_FULLSCREEN);
   2481     pResult->flags |= (flags & SDL_RESIZABLE);
   2482 
   2483     // It might be that the software surface pitch is not the same as
   2484     // the pitch we have, so adjust that!
   2485     pModeInfoFound->uiScanLineSize = pResult->pitch;
   2486 
   2487     // Store new source buffer parameters!
   2488     SDL_memcpy(&(_this->hidden->SrcBufferDesc), pModeInfoFound, sizeof(*pModeInfoFound));
   2489     _this->hidden->pchSrcBuffer = pResult->pixels;
   2490 
   2491 #ifdef DEBUG_BUILD
   2492     printf("[os2fslib_SetVideoMode] : Telling FSLib the stuffs\n"); fflush(stdout);
   2493 #endif
   2494 
   2495     // Tell the FSLib window the new source image format
   2496     FSLib_SetSrcBufferDesc(_this->hidden->hwndClient, &(_this->hidden->SrcBufferDesc));
   2497 
   2498     if (
   2499         ((flags & SDL_RESIZABLE)==0) ||
   2500         (bFirstCall)
   2501        )
   2502     {
   2503       bFirstCall = 0;
   2504 #ifdef DEBUG_BUILD
   2505       printf("[os2fslib_SetVideoMode] : Modifying window size\n"); fflush(stdout);
   2506 #endif
   2507 
   2508       // Calculate frame window size from client window size
   2509       rectl.xLeft = 0;
   2510       rectl.yBottom = 0;
   2511       rectl.xRight = pModeInfoFound->uiXResolution; // Noninclusive
   2512       rectl.yTop = pModeInfoFound->uiYResolution; // Noninclusive
   2513       WinCalcFrameRect(_this->hidden->hwndFrame, &rectl, FALSE);
   2514 
   2515       // Set the new size of the main window
   2516       SetAccessableWindowPos(_this->hidden->hwndFrame,
   2517                              HWND_TOP,
   2518                              0, 0,
   2519                              (rectl.xRight-rectl.xLeft),
   2520                              (rectl.yTop-rectl.yBottom),
   2521                              SWP_SIZE | SWP_ACTIVATE | SWP_SHOW);
   2522     }
   2523 
   2524     // Set fullscreen mode flag, and switch to fullscreen if needed!
   2525     if (flags & SDL_FULLSCREEN)
   2526     {
   2527 #ifdef DEBUG_BUILD
   2528       printf("[os2fslib_SetVideoMode] : Also trying to switch to fullscreen\n");
   2529       fflush(stdout);
   2530 #endif
   2531       FSLib_ToggleFSMode(_this->hidden->hwndClient, 1);
   2532       /* Cursor manager functions to FS mode*/
   2533       os2fslib_SetCursorManagementFunctions(_this, 0);
   2534     } else
   2535     {
   2536 #ifdef DEBUG_BUILD
   2537       printf("[os2fslib_SetVideoMode] : Also trying to switch to desktop mode\n");
   2538       fflush(stdout);
   2539 #endif
   2540       FSLib_ToggleFSMode(_this->hidden->hwndClient, 0);
   2541       /* Cursor manager functions to Windowed mode*/
   2542       os2fslib_SetCursorManagementFunctions(_this, 1);
   2543     }
   2544 
   2545     _this->hidden->pSDLSurface = pResult;
   2546 
   2547     DosReleaseMutexSem(_this->hidden->hmtxUseSrcBuffer);
   2548   } else
   2549   {
   2550 #ifdef DEBUG_BUILD
   2551     printf("[os2fslib_SetVideoMode] : Could not get hmtxUseSrcBuffer!\n"); fflush(stdout);
   2552 #endif
   2553 
   2554     pResult = NULL;
   2555   }
   2556 
   2557   // As we have the new surface, we don't need the current one anymore!
   2558   if ((pResult) && (current))
   2559   {
   2560 #ifdef DEBUG_BUILD
   2561     printf("[os2fslib_SetVideoMode] : Freeing old surface\n"); fflush(stdout);
   2562 #endif
   2563     SDL_FreeSurface(current);
   2564   }
   2565 
   2566   // Redraw window
   2567   WinInvalidateRegion(_this->hidden->hwndClient, NULL, TRUE);
   2568 
   2569   // Now destroy the message queue, if we've created it!
   2570   if (ERRORIDERROR(hmqerror)==0)
   2571   {
   2572 #ifdef DEBUG_BUILD
   2573     printf("[os2fslib_SetVideoMode] : Destroying message queue\n"); fflush(stdout);
   2574 #endif
   2575     WinDestroyMsgQueue(hmq);
   2576   }
   2577 
   2578 #ifdef DEBUG_BUILD
   2579   printf("[os2fslib_SetVideoMode] : Done\n"); fflush(stdout);
   2580 #endif
   2581 
   2582   /* We're done */
   2583 
   2584   // Return with the new surface!
   2585   return pResult;
   2586 }
   2587 
   2588 /* List the available video modes for the given pixel format, sorted
   2589  from largest to smallest.
   2590  */
   2591 static SDL_Rect **os2fslib_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
   2592 {
   2593 #ifdef DEBUG_BUILD
   2594   printf("[os2fslib_ListModes] : ListModes of %d Bpp\n", format->BitsPerPixel);
   2595 #endif
   2596   // Destroy result of previous call, if there is any
   2597   if (_this->hidden->pListModesResult)
   2598   {
   2599     SDL_free(_this->hidden->pListModesResult); _this->hidden->pListModesResult = NULL;
   2600   }
   2601 
   2602   // For resizable and windowed mode we support every resolution!
   2603   if ((flags & SDL_RESIZABLE) && ((flags & SDL_FULLSCREEN) == 0))
   2604     return (SDL_Rect **)-1;
   2605 
   2606   // Check if they need fullscreen or non-fullscreen video modes!
   2607   if ((flags & SDL_FULLSCREEN) == 0)
   2608 
   2609   {
   2610     // For windowed mode we support every resolution!
   2611     return (SDL_Rect **)-1;
   2612   } else
   2613   {
   2614     FSLib_VideoMode_p pFSMode;
   2615     // For fullscreen mode we don't support every resolution!
   2616     // Now create a new list
   2617     pFSMode = _this->hidden->pAvailableFSLibVideoModes;
   2618     while (pFSMode)
   2619     {
   2620       if (pFSMode->uiBPP == format->BitsPerPixel)
   2621       {
   2622         SDL_Rect *pRect = (SDL_Rect *) SDL_malloc(sizeof(SDL_Rect));
   2623         if (pRect)
   2624         {
   2625           // Fill description
   2626           pRect->x = 0;
   2627           pRect->y = 0;
   2628           pRect->w = pFSMode->uiXResolution;
   2629           pRect->h = pFSMode->uiYResolution;
   2630 #ifdef DEBUG_BUILD
   2631 //          printf("!!! Seems to be good!\n");
   2632 //        printf("F: %dx%d\n", pRect->w, pRect->h);
   2633 #endif
   2634           // And insert into list of pRects
   2635           if (!(_this->hidden->pListModesResult))
   2636           {
   2637 #ifdef DEBUG_BUILD
   2638 //            printf("!!! Inserting to beginning\n");
   2639 #endif
   2640 
   2641             // We're the first one to be inserted!
   2642             _this->hidden->pListModesResult = (SDL_Rect**) SDL_malloc(2*sizeof(SDL_Rect*));
   2643             if (_this->hidden->pListModesResult)
   2644             {
   2645               _this->hidden->pListModesResult[0] = pRect;
   2646               _this->hidden->pListModesResult[1] = NULL;
   2647             } else
   2648             {
   2649               SDL_free(pRect);
   2650             }
   2651           } else
   2652           {
   2653             // We're not the first ones, so find the place where we
   2654             // have to insert ourselves
   2655             SDL_Rect **pNewList;
   2656             int iPlace, iNumOfSlots, i;
   2657 
   2658 #ifdef DEBUG_BUILD
   2659 //            printf("!!! Searching where to insert\n");
   2660 #endif
   2661 
   2662             iPlace = -1; iNumOfSlots = 1; // Count the last NULL too!
   2663             for (i=0; _this->hidden->pListModesResult[i]; i++)
   2664             {
   2665               iNumOfSlots++;
   2666               if (iPlace==-1)
   2667               {
   2668                 if ((_this->hidden->pListModesResult[i]->w*_this->hidden->pListModesResult[i]->h)<
   2669                     (pRect->w*pRect->h))
   2670                 {
   2671                   iPlace = i;
   2672                 }
   2673               }
   2674             }
   2675             if (iPlace==-1) iPlace = iNumOfSlots-1;
   2676 
   2677 #ifdef DEBUG_BUILD
   2678 //            printf("!!! From %d slots, it will be at %d\n", iNumOfSlots, iPlace);
   2679 #endif
   2680 
   2681             pNewList = (SDL_Rect**) SDL_realloc(_this->hidden->pListModesResult, (iNumOfSlots+1)*sizeof(SDL_Rect*));
   2682             if (pNewList)
   2683             {
   2684               for (i=iNumOfSlots;i>iPlace;i--)
   2685                 pNewList[i] = pNewList[i-1];
   2686               pNewList[iPlace] = pRect;
   2687               _this->hidden->pListModesResult = pNewList;
   2688             } else
   2689             {
   2690               SDL_free(pRect);
   2691             }
   2692           }
   2693         }
   2694       }
   2695       pFSMode = pFSMode->pNext;
   2696     }
   2697   }
   2698 #ifdef DEBUG_BUILD
   2699 //  printf("Returning list\n");
   2700 #endif
   2701   return _this->hidden->pListModesResult;
   2702 }
   2703 
   2704 /* Initialize the native video subsystem, filling 'vformat' with the
   2705  "best" display pixel format, returning 0 or -1 if there's an error.
   2706  */
   2707 static int os2fslib_VideoInit(_THIS, SDL_PixelFormat *vformat)
   2708 {
   2709   FSLib_VideoMode_p pDesktopMode;
   2710 
   2711 #ifdef DEBUG_BUILD
   2712   printf("[os2fslib_VideoInit] : Enter\n"); fflush(stdout);
   2713 #endif
   2714 
   2715   // Report the best pixel format. For this,
   2716   // we'll use the current desktop format.
   2717   pDesktopMode = FSLib_GetDesktopVideoMode();
   2718   if (!pDesktopMode)
   2719   {
   2720     SDL_SetError("Could not query desktop video mode!");
   2721 #ifdef DEBUG_BUILD
   2722     printf("[os2fslib_VideoInit] : Could not query desktop video mode!\n");
   2723 #endif
   2724     return -1;
   2725   }
   2726 
   2727   /* Determine the current screen size */
   2728   _this->info.current_w = pDesktopMode->uiXResolution;
   2729   _this->info.current_h = pDesktopMode->uiYResolution;
   2730 
   2731   /* Determine the screen depth */
   2732   vformat->BitsPerPixel = pDesktopMode->uiBPP;
   2733   vformat->BytesPerPixel = (vformat->BitsPerPixel+7)/8;
   2734 
   2735   vformat->Rmask = ((unsigned int) pDesktopMode->PixelFormat.ucRedMask) << pDesktopMode->PixelFormat.ucRedPosition;
   2736   vformat->Rshift = pDesktopMode->PixelFormat.ucRedPosition;
   2737   vformat->Rloss = pDesktopMode->PixelFormat.ucRedAdjust;
   2738   vformat->Gmask = ((unsigned int) pDesktopMode->PixelFormat.ucGreenMask) << pDesktopMode->PixelFormat.ucGreenPosition;
   2739   vformat->Gshift = pDesktopMode->PixelFormat.ucGreenPosition;
   2740   vformat->Gloss = pDesktopMode->PixelFormat.ucGreenAdjust;
   2741   vformat->Bmask = ((unsigned int) pDesktopMode->PixelFormat.ucBlueMask) << pDesktopMode->PixelFormat.ucBluePosition;
   2742   vformat->Bshift = pDesktopMode->PixelFormat.ucBluePosition;
   2743   vformat->Bloss = pDesktopMode->PixelFormat.ucBlueAdjust;
   2744   vformat->Amask = ((unsigned int) pDesktopMode->PixelFormat.ucAlphaMask) << pDesktopMode->PixelFormat.ucAlphaPosition;
   2745   vformat->Ashift = pDesktopMode->PixelFormat.ucAlphaPosition;
   2746   vformat->Aloss = pDesktopMode->PixelFormat.ucAlphaAdjust;
   2747 
   2748 #ifdef REPORT_EMPTY_ALPHA_MASK
   2749   vformat->Amask =
   2750       vformat->Ashift =
   2751       vformat->Aloss = 0;
   2752 #endif
   2753 
   2754   // Fill in some window manager capabilities
   2755   _this->info.wm_available = 1;
   2756 
   2757   // Initialize some internal variables
   2758   _this->hidden->pListModesResult = NULL;
   2759   _this->hidden->fInFocus = 0;
   2760   _this->hidden->iSkipWMMOUSEMOVE = 0;
   2761   _this->hidden->iMouseVisible = 1;
   2762 
   2763   if (getenv("SDL_USE_PROPORTIONAL_WINDOW"))
   2764     _this->hidden->bProportionalResize = 1;
   2765   else
   2766   {
   2767     PPIB pib;
   2768     PTIB tib;
   2769     char *pchFileName, *pchTemp;
   2770     char achConfigFile[CCHMAXPATH];
   2771     FILE *hFile;
   2772 
   2773     /* No environment variable to have proportional window.
   2774      * Ok, let's check if this executable is in config file!
   2775      */
   2776     _this->hidden->bProportionalResize = 0;
   2777 
   2778     DosGetInfoBlocks(&tib, &pib);
   2779     pchTemp = pchFileName = pib->pib_pchcmd;
   2780     while (*pchTemp)
   2781     {
   2782       if (*pchTemp=='\\')
   2783         pchFileName = pchTemp+1;
   2784       pchTemp++;
   2785     }
   2786     if (getenv("HOME"))
   2787     {
   2788       sprintf(achConfigFile, "%s\\.sdl.proportionals", getenv("HOME"));
   2789       hFile = fopen(achConfigFile, "rt");
   2790       if (!hFile)
   2791       {
   2792         /* Seems like the file cannot be opened or does not exist.
   2793          * Let's try to create it with defaults!
   2794          */
   2795         hFile = fopen(achConfigFile, "wt");
   2796         if (hFile)
   2797         {
   2798           fprintf(hFile, "; This file is a config file of SDL/2, containing\n");
   2799           fprintf(hFile, "; the list of executables that must have proportional\n");
   2800           fprintf(hFile, "; windows.\n");
   2801           fprintf(hFile, ";\n");
   2802           fprintf(hFile, "; You can add executable filenames into this file,\n");
   2803           fprintf(hFile, "; one under the other. If SDL finds that a given\n");
   2804           fprintf(hFile, "; program is in this list, then that application\n");
   2805           fprintf(hFile, "; will have proportional windows, just like if\n");
   2806           fprintf(hFile, "; the SET SDL_USE_PROPORTIONAL_WINDOW env. variable\n");
   2807           fprintf(hFile, "; would have been set for that process.\n");
   2808           fprintf(hFile, ";\n");
   2809           fprintf(hFile, "\n");
   2810           fprintf(hFile, "dosbox.exe\n");
   2811           fclose(hFile);
   2812         }
   2813 
   2814         hFile = fopen(achConfigFile, "rt");
   2815       }
   2816 
   2817       if (hFile)
   2818       {
   2819         while (fgets(achConfigFile, sizeof(achConfigFile), hFile))
   2820         {
   2821           /* Cut \n from end of string */
   2822 
   2823           while (achConfigFile[strlen(achConfigFile)-1] == '\n')
   2824             achConfigFile[strlen(achConfigFile)-1] = 0;
   2825 
   2826           /* Compare... */
   2827           if (stricmp(achConfigFile, pchFileName)==0)
   2828           {
   2829             /* Found it in config file! */
   2830             _this->hidden->bProportionalResize = 1;
   2831             break;
   2832           }
   2833         }
   2834         fclose(hFile);
   2835       }
   2836     }
   2837   }
   2838 
   2839   DosCreateMutexSem(NULL, &(_this->hidden->hmtxUseSrcBuffer), 0, FALSE);
   2840 
   2841   // Now create our window with a default size
   2842 
   2843   // For this, we select the first available fullscreen mode as
   2844   // current window size!
   2845   SDL_memcpy(&(_this->hidden->SrcBufferDesc), _this->hidden->pAvailableFSLibVideoModes, sizeof(_this->hidden->SrcBufferDesc));
   2846   // Allocate new video buffer!
   2847   _this->hidden->pchSrcBuffer = (char *) SDL_malloc(_this->hidden->pAvailableFSLibVideoModes->uiScanLineSize * _this->hidden->pAvailableFSLibVideoModes->uiYResolution);
   2848   if (!_this->hidden->pchSrcBuffer)
   2849   {
   2850 #ifdef DEBUG_BUILD
   2851     printf("[os2fslib_VideoInit] : Yikes, not enough memory for new video buffer!\n"); fflush(stdout);
   2852 #endif
   2853     SDL_SetError("Not enough memory for new video buffer!\n");
   2854     return -1;
   2855   }
   2856 
   2857   // For this, we need a message processing thread.
   2858   // We'll create a new thread for this, which will do everything
   2859   // what is related to PM
   2860   _this->hidden->iPMThreadStatus = 0;
   2861   _this->hidden->tidPMThread = _beginthread(PMThreadFunc, NULL, 65536, (void *) _this);
   2862   if (_this->hidden->tidPMThread <= 0)
   2863   {
   2864 #ifdef DEBUG_BUILD
   2865     printf("[os2fslib_VideoInit] : Could not create PM thread!\n");
   2866 #endif
   2867     SDL_SetError("Could not create PM thread");
   2868     return -1;
   2869   }
   2870 #ifdef USE_DOSSETPRIORITY
   2871   // Burst the priority of PM Thread!
   2872   DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, _this->hidden->tidPMThread);
   2873 #endif
   2874   // Wait for the PM thread to initialize!
   2875   while (_this->hidden->iPMThreadStatus==0)
   2876     DosSleep(32);
   2877   // If the PM thread could not set up everything, then
   2878   // report an error!
   2879   if (_this->hidden->iPMThreadStatus!=1)
   2880   {
   2881 #ifdef DEBUG_BUILD
   2882     printf("[os2fslib_VideoInit] : PMThread reported an error : %d\n", _this->hidden->iPMThreadStatus);
   2883 #endif
   2884     SDL_SetError("Error initializing PM thread");
   2885     return -1;
   2886   }
   2887 
   2888   return 0;
   2889 }
   2890 
   2891 
   2892 static void os2fslib_DeleteDevice(_THIS)
   2893 {
   2894 #ifdef DEBUG_BUILD
   2895   printf("[os2fslib_DeleteDevice]\n"); fflush(stdout);
   2896 #endif
   2897   // Free used memory
   2898   FSLib_FreeVideoModeList(_this->hidden->pAvailableFSLibVideoModes);
   2899   if (_this->hidden->pListModesResult)
   2900     SDL_free(_this->hidden->pListModesResult);
   2901   if (_this->hidden->pchSrcBuffer)
   2902     SDL_free(_this->hidden->pchSrcBuffer);
   2903   DosCloseMutexSem(_this->hidden->hmtxUseSrcBuffer);
   2904   SDL_free(_this->hidden);
   2905   SDL_free(_this);
   2906   FSLib_Uninitialize();
   2907 }
   2908 
   2909 static int os2fslib_Available(void)
   2910 {
   2911 
   2912   // If we can run, it means that we could load FSLib,
   2913   // so we assume that it's available then!
   2914   return 1;
   2915 }
   2916 
   2917 static void os2fslib_MorphToPM()
   2918 {
   2919   PPIB pib;
   2920   PTIB tib;
   2921 
   2922   DosGetInfoBlocks(&tib, &pib);
   2923 
   2924   // Change flag from VIO to PM:
   2925   if (pib->pib_ultype==2) pib->pib_ultype = 3;
   2926 }
   2927 
   2928 static SDL_VideoDevice *os2fslib_CreateDevice(int devindex)
   2929 {
   2930   SDL_VideoDevice *device;
   2931 
   2932 #ifdef DEBUG_BUILD
   2933   printf("[os2fslib_CreateDevice] : Enter\n"); fflush(stdout);
   2934 #endif
   2935 
   2936   /* Initialize all variables that we clean on shutdown */
   2937   device = (SDL_VideoDevice *)SDL_malloc(sizeof(SDL_VideoDevice));
   2938   if ( device )
   2939   {
   2940     SDL_memset(device, 0, (sizeof *device));
   2941     // Also allocate memory for private data
   2942     device->hidden = (struct SDL_PrivateVideoData *) SDL_malloc((sizeof(struct SDL_PrivateVideoData)));
   2943   }
   2944   if ( (device == NULL) || (device->hidden == NULL) )
   2945   {
   2946     SDL_OutOfMemory();
   2947     if ( device )
   2948       SDL_free(device);
   2949     return NULL;
   2950   }
   2951   SDL_memset(device->hidden, 0, (sizeof *device->hidden));
   2952 
   2953   /* Set the function pointers */
   2954 #ifdef DEBUG_BUILD
   2955   printf("[os2fslib_CreateDevice] : VideoInit is %p\n", os2fslib_VideoInit); fflush(stdout);
   2956 #endif
   2957 
   2958   /* Initialization/Query functions */
   2959   device->VideoInit = os2fslib_VideoInit;
   2960   device->ListModes = os2fslib_ListModes;
   2961   device->SetVideoMode = os2fslib_SetVideoMode;
   2962   device->ToggleFullScreen = os2fslib_ToggleFullScreen;
   2963   device->UpdateMouse = os2fslib_UpdateMouse;
   2964   device->CreateYUVOverlay = NULL;
   2965   device->SetColors = os2fslib_SetColors;
   2966   device->UpdateRects = os2fslib_UpdateRects;
   2967   device->VideoQuit = os2fslib_VideoQuit;
   2968   /* Hardware acceleration functions */
   2969   device->AllocHWSurface = os2fslib_AllocHWSurface;
   2970   device->CheckHWBlit = NULL;
   2971   device->FillHWRect = NULL;
   2972   device->SetHWColorKey = NULL;
   2973   device->SetHWAlpha = NULL;
   2974   device->LockHWSurface = os2fslib_LockHWSurface;
   2975   device->UnlockHWSurface = os2fslib_UnlockHWSurface;
   2976   device->FlipHWSurface = NULL;
   2977   device->FreeHWSurface = os2fslib_FreeHWSurface;
   2978   /* Window manager functions */
   2979   device->SetCaption = os2fslib_SetCaption;
   2980   device->SetIcon = os2fslib_SetIcon;
   2981   device->IconifyWindow = os2fslib_IconifyWindow;
   2982   device->GrabInput = os2fslib_GrabInput;
   2983   device->GetWMInfo = NULL;
   2984   /* Cursor manager functions to Windowed mode*/
   2985   os2fslib_SetCursorManagementFunctions(device, 1);
   2986   /* Event manager functions */
   2987   device->InitOSKeymap = os2fslib_InitOSKeymap;
   2988   device->PumpEvents = os2fslib_PumpEvents;
   2989   /* The function used to dispose of this structure */
   2990   device->free = os2fslib_DeleteDevice;
   2991 
   2992   // Make sure we'll be able to use Win* API even if the application
   2993   // was linked to be a VIO application!
   2994   os2fslib_MorphToPM();
   2995 
   2996   // Now initialize FSLib, and query available video modes!
   2997   if (!FSLib_Initialize())
   2998   {
   2999     // Could not initialize FSLib!
   3000 #ifdef DEBUG_BUILD
   3001     printf("[os2fslib_CreateDevice] : Could not initialize FSLib!\n");
   3002 #endif
   3003     SDL_SetError("Could not initialize FSLib!");
   3004     SDL_free(device->hidden);
   3005     SDL_free(device);
   3006     return NULL;
   3007   }
   3008   device->hidden->pAvailableFSLibVideoModes =
   3009     FSLib_GetVideoModeList();
   3010 
   3011   return device;
   3012 }
   3013 
   3014 VideoBootStrap OS2FSLib_bootstrap = {
   3015         "os2fslib", "OS/2 Video Output using FSLib",
   3016         os2fslib_Available, os2fslib_CreateDevice
   3017 };
   3018 
   3019