1/*
2    SDL - Simple DirectMedia Layer
3    Copyright (C) 1997-2012 Sam Lantinga
4
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Library General Public
7    License as published by the Free Software Foundation; either
8    version 2 of the License, or (at your option) any later version.
9
10    This library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Library General Public License for more details.
14
15    You should have received a copy of the GNU Library General Public
16    License along with this library; if not, write to the Free
17    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
19    Sam Lantinga
20    slouken@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
40static ULONG ulFCFToUse =
41        FCF_TITLEBAR |
42        FCF_SYSMENU |
43        FCF_MINBUTTON |
44        FCF_MAXBUTTON |
45        FCF_NOBYTEALIGN |
46        FCF_SIZEBORDER |
47        FCF_TASKLIST;
48
49static int bMouseCaptured   = 0;
50static int bMouseCapturable = 0;
51static HPOINTER hptrGlobalPointer = NULL;
52static HPOINTER hptrCurrentIcon = NULL;
53static int iWindowSizeX = 320;
54static int iWindowSizeY = 200;
55static int bWindowResized = 0;
56
57#pragma pack(1)
58typedef struct BMPINFO
59{
60   BITMAPINFO;
61   RGB  clr;
62} BMPINFO, *PBMPINFO;
63#pragma pack()
64
65
66// Backdoors:
67DECLSPEC 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 */
94static SDLKey HWScanKeyMap[256];
95static SDL_keysym *TranslateKey(int vkey, int chcode, int scancode, SDL_keysym *keysym, int iPressed);
96static 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/////////////////////////////////////////////////////////////////////
122static 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
177static 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/////////////////////////////////////////////////////////////////////
236static 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/////////////////////////////////////////////////////////////////////
382static 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/////////////////////////////////////////////////////////////////////
1052static 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/////////////////////////////////////////////////////////////////////
1144int iNumOfPMThreadInstances = 0; // Global!
1145static 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
1308struct WMcursor
1309{
1310  HBITMAP hbm;
1311  HPOINTER hptr;
1312  char *pchData;
1313};
1314
1315/* Free a window manager cursor */
1316void 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 */
1328static void memnot(Uint8 *dst, Uint8 *src, int len)
1329{
1330  while ( len-- > 0 )
1331    *dst++ = ~*src++;
1332}
1333static 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 */
1340WMcursor *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
1451WMcursor *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 */
1463int 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 */
1492void 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 */
1514void 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 */
1539void os2fslib_CheckMouseMode(_THIS)
1540{
1541}
1542
1543static 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 */
1581static int os2fslib_AllocHWSurface(_THIS, SDL_Surface *surface)
1582{
1583  return(-1);
1584}
1585static void os2fslib_FreeHWSurface(_THIS, SDL_Surface *surface)
1586{
1587  return;
1588}
1589
1590/* We need to wait for vertical retrace on page flipped displays */
1591static int os2fslib_LockHWSurface(_THIS, SDL_Surface *surface)
1592{
1593  return(0);
1594}
1595
1596static void os2fslib_UnlockHWSurface(_THIS, SDL_Surface *surface)
1597{
1598  return;
1599}
1600
1601static 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
1608static 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 */
1624void 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
1795static 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
1817static 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 */
1950int 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
1980static 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 */
2047static 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
2070static 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 */
2088static 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 */
2141static 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 */
2214static 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 */
2295static 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 */
2591static 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 */
2707static 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
2892static 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
2909static 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
2917static 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
2928static 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
3014VideoBootStrap OS2FSLib_bootstrap = {
3015        "os2fslib", "OS/2 Video Output using FSLib",
3016        os2fslib_Available, os2fslib_CreateDevice
3017};
3018
3019