SDL-1.2.14
[sdl_omap.git] / src / video / os2fslib / SDL_os2fslib.c
1 /*
2     SDL - Simple DirectMedia Layer
3     Copyright (C) 1997-2009 Sam Lantinga
4
5     This library is free software; you can redistribute it and/or
6     modify it under the terms of the GNU Library General Public
7     License as published by the Free Software Foundation; either
8     version 2 of the License, or (at your option) any later version.
9
10     This library is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13     Library General Public License for more details.
14
15     You should have received a copy of the GNU Library General Public
16     License along with this library; if not, write to the Free
17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
19     Sam Lantinga
20     slouken@libsdl.org
21 */
22 #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