sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_os2video.c (56871B)


      1 /*
      2   Simple DirectMedia Layer
      3   Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org>
      4 
      5   This software is provided 'as-is', without any express or implied
      6   warranty.  In no event will the authors be held liable for any damages
      7   arising from the use of this software.
      8 
      9   Permission is granted to anyone to use this software for any purpose,
     10   including commercial applications, and to alter it and redistribute it
     11   freely, subject to the following restrictions:
     12 
     13   1. The origin of this software must not be misrepresented; you must not
     14      claim that you wrote the original software. If you use this software
     15      in a product, an acknowledgment in the product documentation would be
     16      appreciated but is not required.
     17   2. Altered source versions must be plainly marked as such, and must not be
     18      misrepresented as being the original software.
     19   3. This notice may not be removed or altered from any source distribution.
     20 */
     21 
     22 #include "../../SDL_internal.h"
     23 
     24 #if SDL_VIDEO_DRIVER_OS2
     25 
     26 #include "SDL_video.h"
     27 #include "SDL_mouse.h"
     28 #include "../SDL_pixels_c.h"
     29 #include "../SDL_shape_internals.h"
     30 #include "../../events/SDL_events_c.h"
     31 #include "SDL_os2video.h"
     32 #include "SDL_syswm.h"
     33 #include "SDL_os2util.h"
     34 
     35 #define __MEERROR_H__
     36 #define  _MEERROR_H_
     37 #include <mmioos2.h>
     38 #include <fourcc.h>
     39 #ifndef FOURCC_R666
     40 #define FOURCC_R666 mmioFOURCC('R','6','6','6')
     41 #endif
     42 
     43 #define WIN_CLIENT_CLASS        "SDL2"
     44 #define OS2DRIVER_NAME_DIVE     "DIVE"
     45 #define OS2DRIVER_NAME_VMAN     "VMAN"
     46 
     47 
     48 static const SDL_Scancode aSDLScancode[] = {
     49          /*   0                       1                           2                           3                           4                        5                                                       6                           7 */
     50          /*   8                       9                           A                           B                           C                        D                                                       E                           F */
     51          SDL_SCANCODE_UNKNOWN,        SDL_SCANCODE_ESCAPE,        SDL_SCANCODE_1,             SDL_SCANCODE_2,             SDL_SCANCODE_3,          SDL_SCANCODE_4,             SDL_SCANCODE_5,             SDL_SCANCODE_6,          /* 0 */
     52          SDL_SCANCODE_7,              SDL_SCANCODE_8,             SDL_SCANCODE_9,             SDL_SCANCODE_0,             SDL_SCANCODE_MINUS,      SDL_SCANCODE_EQUALS,        SDL_SCANCODE_BACKSPACE,     SDL_SCANCODE_TAB,        /* 0 */
     53 
     54          SDL_SCANCODE_Q,              SDL_SCANCODE_W,             SDL_SCANCODE_E,             SDL_SCANCODE_R,             SDL_SCANCODE_T,          SDL_SCANCODE_Y,             SDL_SCANCODE_U,             SDL_SCANCODE_I,          /* 1 */
     55          SDL_SCANCODE_O,              SDL_SCANCODE_P,             SDL_SCANCODE_LEFTBRACKET,   SDL_SCANCODE_RIGHTBRACKET,  SDL_SCANCODE_RETURN,     SDL_SCANCODE_LCTRL,         SDL_SCANCODE_A,             SDL_SCANCODE_S,          /* 1 */
     56 
     57          SDL_SCANCODE_D,              SDL_SCANCODE_F,             SDL_SCANCODE_G,             SDL_SCANCODE_H,             SDL_SCANCODE_J,          SDL_SCANCODE_K,             SDL_SCANCODE_L,             SDL_SCANCODE_SEMICOLON,  /* 2 */
     58          SDL_SCANCODE_APOSTROPHE,     SDL_SCANCODE_GRAVE,         SDL_SCANCODE_LSHIFT,        SDL_SCANCODE_BACKSLASH,     SDL_SCANCODE_Z,          SDL_SCANCODE_X,             SDL_SCANCODE_C,             SDL_SCANCODE_V,          /* 2 */
     59 
     60          SDL_SCANCODE_B,              SDL_SCANCODE_N,             SDL_SCANCODE_M,             SDL_SCANCODE_COMMA,         SDL_SCANCODE_PERIOD,     SDL_SCANCODE_SLASH,         SDL_SCANCODE_RSHIFT,  /*55*/SDL_SCANCODE_KP_MULTIPLY,/* 3 */
     61          SDL_SCANCODE_LALT,           SDL_SCANCODE_SPACE,         SDL_SCANCODE_CAPSLOCK,      SDL_SCANCODE_F1,            SDL_SCANCODE_F2,         SDL_SCANCODE_F3,            SDL_SCANCODE_F4,            SDL_SCANCODE_F5,         /* 3 */
     62 
     63          SDL_SCANCODE_F6,             SDL_SCANCODE_F7,            SDL_SCANCODE_F8,            SDL_SCANCODE_F9,            SDL_SCANCODE_F10,        SDL_SCANCODE_NUMLOCKCLEAR,  SDL_SCANCODE_SCROLLLOCK,    SDL_SCANCODE_KP_7,       /* 4 */
     64  /*72*/  SDL_SCANCODE_KP_8,     /*73*/SDL_SCANCODE_KP_9,          SDL_SCANCODE_KP_MINUS,/*75*/SDL_SCANCODE_KP_4,    /*76*/SDL_SCANCODE_KP_5, /*77*/SDL_SCANCODE_KP_6,    /*78*/SDL_SCANCODE_KP_PLUS, /*79*/SDL_SCANCODE_KP_1,       /* 4 */
     65 
     66  /*80*/  SDL_SCANCODE_KP_2,     /*81*/SDL_SCANCODE_KP_3,          SDL_SCANCODE_KP_0,    /*83*/SDL_SCANCODE_KP_PERIOD,     SDL_SCANCODE_UNKNOWN,    SDL_SCANCODE_UNKNOWN,       SDL_SCANCODE_NONUSBACKSLASH,SDL_SCANCODE_F11,        /* 5 */
     67  /*88*/  SDL_SCANCODE_F12,      /*89*/SDL_SCANCODE_PAUSE,   /*90*/SDL_SCANCODE_KP_ENTER,/*91*/SDL_SCANCODE_RCTRL,   /*92*/SDL_SCANCODE_KP_DIVIDE,  SDL_SCANCODE_APPLICATION,   SDL_SCANCODE_RALT,    /*95*/SDL_SCANCODE_UNKNOWN,    /* 5 */
     68 
     69  /*96*/  SDL_SCANCODE_HOME,     /*97*/SDL_SCANCODE_UP,      /*98*/SDL_SCANCODE_PAGEUP,        SDL_SCANCODE_LEFT,   /*100*/SDL_SCANCODE_RIGHT,      SDL_SCANCODE_END,    /*102*/SDL_SCANCODE_DOWN,   /*103*/SDL_SCANCODE_PAGEDOWN,   /* 6 */
     70 /*104*/  SDL_SCANCODE_F17,     /*105*/SDL_SCANCODE_DELETE,        SDL_SCANCODE_F19,           SDL_SCANCODE_UNKNOWN,       SDL_SCANCODE_UNKNOWN,    SDL_SCANCODE_UNKNOWN,/*110*/SDL_SCANCODE_UNKNOWN,/*111*/SDL_SCANCODE_UNKNOWN,    /* 6 */
     71 
     72 /*112*/  SDL_SCANCODE_INTERNATIONAL2, SDL_SCANCODE_UNKNOWN,       SDL_SCANCODE_UNKNOWN,       SDL_SCANCODE_INTERNATIONAL1,SDL_SCANCODE_UNKNOWN,    SDL_SCANCODE_UNKNOWN,       SDL_SCANCODE_UNKNOWN,       SDL_SCANCODE_UNKNOWN,    /* 7 */
     73 /*120*/  SDL_SCANCODE_UNKNOWN,        SDL_SCANCODE_INTERNATIONAL4,SDL_SCANCODE_UNKNOWN,       SDL_SCANCODE_INTERNATIONAL5,SDL_SCANCODE_APPLICATION,SDL_SCANCODE_INTERNATIONAL3,SDL_SCANCODE_LGUI,          SDL_SCANCODE_RGUI        /* 7 */
     74 };
     75 
     76 /*  Utilites.
     77  *  ---------
     78  */
     79 static BOOL _getSDLPixelFormatData(SDL_PixelFormat *pSDLPixelFormat,
     80                                    ULONG ulBPP, ULONG fccColorEncoding)
     81 {
     82     ULONG   ulRshift, ulGshift, ulBshift;
     83     ULONG   ulRmask, ulGmask, ulBmask;
     84     ULONG   ulRloss, ulGloss, ulBloss;
     85 
     86     pSDLPixelFormat->BitsPerPixel = ulBPP;
     87     pSDLPixelFormat->BytesPerPixel = (pSDLPixelFormat->BitsPerPixel + 7) / 8;
     88 
     89     switch (fccColorEncoding) {
     90     case FOURCC_LUT8:
     91         ulRshift = 0; ulGshift = 0; ulBshift = 0;
     92         ulRmask = 0; ulGmask = 0; ulBmask = 0;
     93         ulRloss = 8; ulGloss = 8; ulBloss = 8;
     94         break;
     95 
     96     case FOURCC_R555:
     97         ulRshift = 10; ulGshift = 5; ulBshift = 0;
     98         ulRmask = 0x7C00; ulGmask = 0x03E0; ulBmask = 0x001F;
     99         ulRloss = 3; ulGloss = 3; ulBloss = 3;
    100         break;
    101 
    102     case FOURCC_R565:
    103         ulRshift = 11; ulGshift = 5; ulBshift = 0;
    104         ulRmask = 0xF800; ulGmask = 0x07E0; ulBmask = 0x001F;
    105         ulRloss = 3; ulGloss = 2; ulBloss = 3;
    106         break;
    107 
    108     case FOURCC_R664:
    109         ulRshift = 10; ulGshift = 4; ulBshift = 0;
    110         ulRmask = 0xFC00; ulGmask = 0x03F0; ulBmask = 0x000F;
    111         ulRloss = 2; ulGloss = 4; ulBloss = 3;
    112         break;
    113 
    114     case FOURCC_R666:
    115         ulRshift = 12; ulGshift = 6; ulBshift = 0;
    116         ulRmask = 0x03F000; ulGmask = 0x000FC0; ulBmask = 0x00003F;
    117         ulRloss = 2; ulGloss = 2; ulBloss = 2;
    118         break;
    119 
    120     case FOURCC_RGB3:
    121     case FOURCC_RGB4:
    122         ulRshift = 0; ulGshift = 8; ulBshift = 16;
    123         ulRmask = 0x0000FF; ulGmask = 0x00FF00; ulBmask = 0xFF0000;
    124         ulRloss = 0x00; ulGloss = 0x00; ulBloss = 0x00;
    125         break;
    126 
    127     case FOURCC_BGR3:
    128     case FOURCC_BGR4:
    129         ulRshift = 16; ulGshift = 8; ulBshift = 0;
    130         ulRmask = 0xFF0000; ulGmask = 0x00FF00; ulBmask = 0x0000FF;
    131         ulRloss = 0; ulGloss = 0; ulBloss = 0;
    132         break;
    133 
    134     default:
    135 /*      printf("Unknown color encoding: %.4s\n", fccColorEncoding);*/
    136         memset(pSDLPixelFormat, 0, sizeof(SDL_PixelFormat));
    137         return FALSE;
    138     }
    139 
    140     pSDLPixelFormat->Rshift = ulRshift;
    141     pSDLPixelFormat->Gshift = ulGshift;
    142     pSDLPixelFormat->Bshift = ulBshift;
    143     pSDLPixelFormat->Rmask  = ulRmask;
    144     pSDLPixelFormat->Gmask  = ulGmask;
    145     pSDLPixelFormat->Bmask  = ulBmask;
    146     pSDLPixelFormat->Rloss  = ulRloss;
    147     pSDLPixelFormat->Gloss  = ulGloss;
    148     pSDLPixelFormat->Bloss  = ulBloss;
    149 
    150     pSDLPixelFormat->Ashift = 0x00;
    151     pSDLPixelFormat->Amask  = 0x00;
    152     pSDLPixelFormat->Aloss  = 0x00;
    153 
    154     return TRUE;
    155 }
    156 
    157 static Uint32 _getSDLPixelFormat(ULONG ulBPP, FOURCC fccColorEncoding)
    158 {
    159     SDL_PixelFormat stSDLPixelFormat;
    160     Uint32          uiResult = SDL_PIXELFORMAT_UNKNOWN;
    161 
    162     if (_getSDLPixelFormatData(&stSDLPixelFormat, ulBPP, fccColorEncoding))
    163         uiResult = SDL_MasksToPixelFormatEnum(ulBPP, stSDLPixelFormat.Rmask,
    164                                               stSDLPixelFormat.Gmask,
    165                                               stSDLPixelFormat.Bmask, 0);
    166 
    167     return uiResult;
    168 }
    169 
    170 static SDL_DisplayMode *_getDisplayModeForSDLWindow(SDL_Window *window)
    171 {
    172     SDL_VideoDisplay *pSDLDisplay = SDL_GetDisplayForWindow(window);
    173 
    174     if (pSDLDisplay == NULL) {
    175         debug_os2("No display for the window");
    176         return FALSE;
    177     }
    178 
    179     return &pSDLDisplay->current_mode;
    180 }
    181 
    182 static VOID _mouseCheck(WINDATA *pWinData)
    183 {
    184     SDL_Mouse *pSDLMouse = SDL_GetMouse();
    185 
    186     if ((pSDLMouse->relative_mode || (pWinData->window->flags & SDL_WINDOW_INPUT_GRABBED) != 0) &&
    187         ((pWinData->window->flags & SDL_WINDOW_INPUT_FOCUS) != 0)) {
    188         /* We will make a real capture in _wmMouseButton() */
    189     } else {
    190         WinSetCapture(HWND_DESKTOP, NULLHANDLE);
    191     }
    192 }
    193 
    194 
    195 /*  PM window procedure.
    196  *  --------------------
    197  */
    198 static int OS2_ResizeWindowShape(SDL_Window *window);
    199 
    200 static VOID _setVisibleRegion(WINDATA *pWinData, BOOL fVisible)
    201 {
    202     SDL_VideoDisplay *pSDLDisplay;
    203 
    204     if (! pWinData->pVOData)
    205         return;
    206 
    207      pSDLDisplay = (fVisible)? SDL_GetDisplayForWindow(pWinData->window) : NULL;
    208      pWinData->pOutput->SetVisibleRegion(pWinData->pVOData, pWinData->hwnd,
    209                                          (pSDLDisplay == NULL) ?
    210                                             NULL : &pSDLDisplay->current_mode,
    211                                          pWinData->hrgnShape, fVisible);
    212 }
    213 
    214 static VOID _wmPaint(WINDATA *pWinData, HWND hwnd)
    215 {
    216     if (pWinData->pVOData == NULL ||
    217         !pWinData->pOutput->Update(pWinData->pVOData, hwnd, NULL, 0)) {
    218         RECTL   rectl;
    219         HPS     hps;
    220 
    221         hps = WinBeginPaint(hwnd, 0, &rectl);
    222         WinFillRect(hps, &rectl, CLR_BLACK);
    223         WinEndPaint(hps);
    224     }
    225 }
    226 
    227 static VOID _wmMouseMove(WINDATA *pWinData, SHORT lX, SHORT lY)
    228 {
    229     SDL_Mouse *pSDLMouse = SDL_GetMouse();
    230     POINTL  pointl;
    231     BOOL    fWinActive = (pWinData->window->flags & SDL_WINDOW_INPUT_FOCUS) != 0;
    232 
    233     if (!pSDLMouse->relative_mode || pSDLMouse->relative_mode_warp) {
    234         if (!pSDLMouse->relative_mode && fWinActive &&
    235             ((pWinData->window->flags & SDL_WINDOW_INPUT_GRABBED) != 0) &&
    236             (WinQueryCapture(HWND_DESKTOP) == pWinData->hwnd)) {
    237 
    238             pointl.x = lX;
    239             pointl.y = lY;
    240 
    241             if (lX < 0)
    242                 lX = 0;
    243             else if (lX >= pWinData->window->w)
    244                 lX = pWinData->window->w - 1;
    245 
    246             if (lY < 0)
    247                 lY = 0;
    248             else if (lY >= pWinData->window->h)
    249                 lY = pWinData->window->h - 1;
    250 
    251             if (lX != pointl.x || lY != pointl.x) {
    252                 pointl.x = lX;
    253                 pointl.y = lY;
    254                 WinMapWindowPoints(pWinData->hwnd, HWND_DESKTOP, &pointl, 1);
    255                 pWinData->lSkipWMMouseMove++;
    256                 WinSetPointerPos(HWND_DESKTOP, pointl.x, pointl.y);
    257             }
    258         }
    259 
    260         SDL_SendMouseMotion(pWinData->window, 0, 0, lX,
    261                             pWinData->window->h - lY - 1);
    262         return;
    263     }
    264 
    265     if (fWinActive) {
    266         pointl.x = pWinData->window->w / 2;
    267         pointl.y = pWinData->window->h / 2;
    268         WinMapWindowPoints(pWinData->hwnd, HWND_DESKTOP, &pointl, 1);
    269 
    270         SDL_SendMouseMotion(pWinData->window, 0, 1,
    271                             lX - pointl.x, pointl.y - lY);
    272 
    273         pWinData->lSkipWMMouseMove++;
    274         WinSetPointerPos(HWND_DESKTOP, pointl.x, pointl.y);
    275     }
    276 }
    277 
    278 static VOID _wmMouseButton(WINDATA *pWinData, ULONG ulButton, BOOL fDown)
    279 {
    280     static ULONG  aBtnGROP2SDL[3] = { SDL_BUTTON_LEFT, SDL_BUTTON_RIGHT,
    281                                       SDL_BUTTON_MIDDLE };
    282     SDL_Mouse *pSDLMouse = SDL_GetMouse();
    283 
    284     if ((pSDLMouse->relative_mode || ((pWinData->window->flags & SDL_WINDOW_INPUT_GRABBED) != 0)) &&
    285         ((pWinData->window->flags & SDL_WINDOW_INPUT_FOCUS) != 0) &&
    286         (WinQueryCapture(HWND_DESKTOP) != pWinData->hwnd)) {
    287         /* Mouse should be captured. */
    288         if (pSDLMouse->relative_mode && !pSDLMouse->relative_mode_warp) {
    289             POINTL  pointl;
    290 
    291             pointl.x = pWinData->window->w / 2;
    292             pointl.y = pWinData->window->h / 2;
    293             WinMapWindowPoints(pWinData->hwnd, HWND_DESKTOP, &pointl, 1);
    294             pWinData->lSkipWMMouseMove++;
    295             WinSetPointerPos(HWND_DESKTOP, pointl.x, pointl.y);
    296         }
    297 
    298         WinSetCapture(HWND_DESKTOP, pWinData->hwnd);
    299     }
    300 
    301     SDL_SendMouseButton(pWinData->window, 0,
    302                         (fDown)? SDL_PRESSED : SDL_RELEASED,
    303                         aBtnGROP2SDL[ulButton]);
    304 }
    305 
    306 static VOID _wmChar(WINDATA *pWinData, MPARAM mp1, MPARAM mp2)
    307 {
    308     ULONG   ulFlags = SHORT1FROMMP(mp1);      /* WM_CHAR flags         */
    309     ULONG   ulVirtualKey = SHORT2FROMMP(mp2); /* Virtual key code VK_* */
    310     ULONG   ulCharCode = SHORT1FROMMP(mp2);   /* Character code        */
    311     ULONG   ulScanCode = CHAR4FROMMP(mp1);    /* Scan code             */
    312 
    313     if (((ulFlags & (KC_VIRTUALKEY | KC_KEYUP | KC_ALT)) == (KC_VIRTUALKEY | KC_ALT)) &&
    314         (ulVirtualKey == VK_F4)) {
    315         SDL_SendWindowEvent(pWinData->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
    316     }
    317 
    318     if ((ulFlags & KC_SCANCODE) != 0) {
    319         SDL_SendKeyboardKey(((ulFlags & KC_KEYUP) == 0)? SDL_PRESSED : SDL_RELEASED, aSDLScancode[ulScanCode]);
    320     }
    321 
    322     if ((ulFlags & KC_CHAR) != 0) {
    323         CHAR    acUTF8[4];
    324         LONG    lRC = StrUTF8(1, acUTF8, sizeof(acUTF8), (PSZ)&ulCharCode, 1);
    325 
    326         SDL_SendKeyboardText((lRC > 0)? acUTF8 : (PSZ)&ulCharCode);
    327     }
    328 }
    329 
    330 static VOID _wmMove(WINDATA *pWinData)
    331 {
    332     SDL_DisplayMode *pSDLDisplayMode = _getDisplayModeForSDLWindow(pWinData->window);
    333     POINTL  pointl = { 0 };
    334     RECTL   rectl;
    335 
    336     WinQueryWindowRect(pWinData->hwnd, &rectl);
    337     WinMapWindowPoints(pWinData->hwnd, HWND_DESKTOP, (PPOINTL)&rectl, 2);
    338 
    339     WinMapWindowPoints(pWinData->hwnd, HWND_DESKTOP, &pointl, 1);
    340     SDL_SendWindowEvent(pWinData->window, SDL_WINDOWEVENT_MOVED, rectl.xLeft,
    341                        pSDLDisplayMode->h - rectl.yTop);
    342 }
    343 
    344 static MRESULT _wmDragOver(WINDATA *pWinData, PDRAGINFO pDragInfo)
    345 {
    346     ULONG       ulIdx;
    347     PDRAGITEM   pDragItem;
    348     USHORT      usDrag   = DOR_NEVERDROP;
    349     USHORT      usDragOp = DO_UNKNOWN;
    350 
    351     if (!DrgAccessDraginfo(pDragInfo))
    352         return MRFROM2SHORT(DOR_NEVERDROP, DO_UNKNOWN);
    353 
    354     for (ulIdx = 0; ulIdx < pDragInfo->cditem; ulIdx++) {
    355         pDragItem = DrgQueryDragitemPtr(pDragInfo, ulIdx);
    356 
    357         /* We accept WPS files only. */
    358         if (!DrgVerifyRMF(pDragItem, "DRM_OS2FILE", NULL)) {
    359             usDrag   = DOR_NEVERDROP;
    360             usDragOp = DO_UNKNOWN;
    361             break;
    362         }
    363 
    364         if (pDragInfo->usOperation == DO_DEFAULT &&
    365             (pDragItem->fsSupportedOps & DO_COPYABLE) != 0) {
    366             usDrag   = DOR_DROP;
    367             usDragOp = DO_COPY;
    368         } else
    369         if (pDragInfo->usOperation == DO_LINK &&
    370             (pDragItem->fsSupportedOps & DO_LINKABLE) != 0) {
    371             usDrag   = DOR_DROP;
    372             usDragOp = DO_LINK;
    373         } else {
    374             usDrag   = DOR_NODROPOP;
    375             usDragOp = DO_UNKNOWN;
    376             break;
    377         }
    378     }
    379 
    380     /* Update window (The DIVE surface spoiled while dragging) */
    381     WinInvalidateRect(pWinData->hwnd, NULL, FALSE);
    382     WinUpdateWindow(pWinData->hwnd);
    383 
    384     DrgFreeDraginfo(pDragInfo);
    385     return MPFROM2SHORT(usDrag, usDragOp);
    386 }
    387 
    388 static MRESULT _wmDrop(WINDATA *pWinData, PDRAGINFO pDragInfo)
    389 {
    390     ULONG       ulIdx;
    391     PDRAGITEM   pDragItem;
    392     CHAR        acFName[_MAX_PATH];
    393     PCHAR       pcFName;
    394 
    395     if (!DrgAccessDraginfo(pDragInfo))
    396         return MRFROM2SHORT(DOR_NEVERDROP, 0);
    397 
    398     for (ulIdx = 0; ulIdx < pDragInfo->cditem; ulIdx++) {
    399         pDragItem = DrgQueryDragitemPtr(pDragInfo, ulIdx);
    400 
    401         if (DrgVerifyRMF(pDragItem, "DRM_OS2FILE", NULL) &&
    402             pDragItem->hstrContainerName != NULLHANDLE &&
    403             pDragItem->hstrSourceName != NULLHANDLE) {
    404             /* Get file name from the item. */
    405             DrgQueryStrName(pDragItem->hstrContainerName, sizeof(acFName), acFName);
    406             pcFName = strchr(acFName, '\0');
    407             DrgQueryStrName(pDragItem->hstrSourceName,
    408                             sizeof(acFName) - (pcFName - acFName), pcFName);
    409 
    410             /* Send to SDL full file name converted to UTF-8. */
    411             pcFName = OS2_SysToUTF8(acFName);
    412             SDL_SendDropFile(pWinData->window, pcFName);
    413             SDL_free(pcFName);
    414 
    415             /* Notify a source that a drag operation is complete. */
    416             if (pDragItem->hwndItem)
    417                 DrgSendTransferMsg(pDragItem->hwndItem, DM_ENDCONVERSATION,
    418                                    (MPARAM)pDragItem->ulItemID,
    419                                    (MPARAM)DMFL_TARGETSUCCESSFUL);
    420         }
    421     }
    422 
    423     DrgDeleteDraginfoStrHandles(pDragInfo);
    424     DrgFreeDraginfo(pDragInfo);
    425 
    426     SDL_SendDropComplete(pWinData->window);
    427 
    428     return (MRESULT)FALSE;
    429 }
    430 
    431 MRESULT EXPENTRY wndFrameProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
    432 {
    433     HWND    hwndClient = WinQueryWindow(hwnd, QW_BOTTOM);
    434     WINDATA * pWinData = (WINDATA *)WinQueryWindowULong(hwndClient, 0);
    435 
    436     if (pWinData == NULL)
    437         return WinDefWindowProc(hwnd, msg, mp1, mp2);
    438 
    439     /* Send a SDL_SYSWMEVENT if the application wants them */
    440     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
    441         SDL_SysWMmsg wmmsg;
    442 
    443         SDL_VERSION(&wmmsg.version);
    444         wmmsg.subsystem = SDL_SYSWM_OS2;
    445         wmmsg.msg.os2.fFrame = TRUE;
    446         wmmsg.msg.os2.hwnd = hwnd;
    447         wmmsg.msg.os2.msg = msg;
    448         wmmsg.msg.os2.mp1 = mp1;
    449         wmmsg.msg.os2.mp2 = mp2;
    450         SDL_SendSysWMEvent(&wmmsg);
    451     }
    452 
    453     switch (msg) {
    454     case WM_MINMAXFRAME:
    455         if ((((PSWP)mp1)->fl & SWP_RESTORE) != 0) {
    456             pWinData->lSkipWMMove += 2;
    457             SDL_SendWindowEvent(pWinData->window, SDL_WINDOWEVENT_RESTORED, 0, 0);
    458         }
    459         if ((((PSWP)mp1)->fl & SWP_MINIMIZE) != 0) {
    460             pWinData->lSkipWMSize++;
    461             pWinData->lSkipWMMove += 2;
    462             SDL_SendWindowEvent(pWinData->window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
    463         }
    464         if ((((PSWP)mp1)->fl & SWP_MAXIMIZE) != 0) {
    465             SDL_SendWindowEvent(pWinData->window, SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
    466         }
    467         break;
    468 
    469     case WM_ADJUSTFRAMEPOS:
    470         if (pWinData->lSkipWMAdjustFramePos > 0) {
    471             pWinData->lSkipWMAdjustFramePos++;
    472             break;
    473         }
    474         if ((pWinData->window->flags & SDL_WINDOW_FULLSCREEN) != 0 &&
    475             (((PSWP)mp1)->fl & SWP_RESTORE) != 0) {
    476             /* Keep fullscreen window size on restore. */
    477             RECTL rectl;
    478 
    479             rectl.xLeft = 0;
    480             rectl.yBottom = 0;
    481             rectl.xRight = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN);
    482             rectl.yTop = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);
    483             WinCalcFrameRect(hwnd, &rectl, FALSE);
    484             ((PSWP)mp1)->x = rectl.xLeft;
    485             ((PSWP)mp1)->y = rectl.yBottom;
    486             ((PSWP)mp1)->cx = rectl.xRight - rectl.xLeft;
    487             ((PSWP)mp1)->cy = rectl.yTop - rectl.yBottom;
    488         }
    489         if ((((PSWP)mp1)->fl & (SWP_SIZE | SWP_MINIMIZE)) == SWP_SIZE) {
    490             if ((pWinData->window->flags & SDL_WINDOW_FULLSCREEN) != 0) {
    491                 /* SDL_WINDOW_FULLSCREEN_DESKTOP have flag SDL_WINDOW_FULLSCREEN... */
    492                 if (SDL_IsShapedWindow(pWinData->window))
    493                     OS2_ResizeWindowShape(pWinData->window);
    494                 break;
    495             }
    496             if ((SDL_GetWindowFlags(pWinData->window) & SDL_WINDOW_RESIZABLE) != 0) {
    497                 RECTL   rectl;
    498                 int     iMinW, iMinH, iMaxW, iMaxH;
    499                 int     iWinW, iWinH;
    500 
    501                 rectl.xLeft = 0;
    502                 rectl.yBottom = 0;
    503                 SDL_GetWindowSize(pWinData->window,
    504                                   (int *)&rectl.xRight, (int *)&rectl.yTop);
    505                 iWinW = rectl.xRight;
    506                 iWinH = rectl.yTop;
    507 
    508                 SDL_GetWindowMinimumSize(pWinData->window, &iMinW, &iMinH);
    509                 SDL_GetWindowMaximumSize(pWinData->window, &iMaxW, &iMaxH);
    510 
    511                 if (iWinW < iMinW)
    512                     rectl.xRight = iMinW;
    513                 else if (iMaxW != 0 && iWinW > iMaxW)
    514                     rectl.xRight = iMaxW;
    515 
    516                 if (iWinH < iMinH)
    517                     rectl.yTop = iMinW;
    518                 else if (iMaxH != 0 && iWinH > iMaxH)
    519                     rectl.yTop = iMaxH;
    520 
    521                 if (rectl.xRight == iWinW && rectl.yTop == iWinH) {
    522                     if (SDL_IsShapedWindow(pWinData->window))
    523                         OS2_ResizeWindowShape(pWinData->window);
    524                     break;
    525                 }
    526 
    527                 WinCalcFrameRect(hwnd, &rectl, FALSE);
    528                 ((PSWP)mp1)->cx = rectl.xRight - rectl.xLeft;
    529                 ((PSWP)mp1)->cy = rectl.yTop - rectl.yBottom;
    530             }
    531         }
    532         break;
    533     }
    534 
    535     return pWinData->fnWndFrameProc(hwnd, msg, mp1, mp2);
    536 }
    537 
    538 MRESULT EXPENTRY wndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
    539 {
    540     WINDATA *pWinData = (WINDATA *)WinQueryWindowULong(hwnd, 0);
    541 
    542     if (pWinData == NULL)
    543         return WinDefWindowProc(hwnd, msg, mp1, mp2);
    544 
    545     /* Send a SDL_SYSWMEVENT if the application wants them */
    546     if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
    547         SDL_SysWMmsg wmmsg;
    548 
    549         SDL_VERSION(&wmmsg.version);
    550         wmmsg.subsystem = SDL_SYSWM_OS2;
    551         wmmsg.msg.os2.fFrame = FALSE;
    552         wmmsg.msg.os2.hwnd = hwnd;
    553         wmmsg.msg.os2.msg = msg;
    554         wmmsg.msg.os2.mp1 = mp1;
    555         wmmsg.msg.os2.mp2 = mp2;
    556         SDL_SendSysWMEvent(&wmmsg);
    557     }
    558 
    559     switch (msg) {
    560     case WM_CLOSE:
    561     case WM_QUIT:
    562         SDL_SendWindowEvent(pWinData->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
    563         if (pWinData->fnUserWndProc == NULL)
    564             return (MRESULT)FALSE;
    565         break;
    566 
    567     case WM_PAINT:
    568         _wmPaint(pWinData, hwnd);
    569         break;
    570 
    571     case WM_SHOW:
    572         SDL_SendWindowEvent(pWinData->window, (SHORT1FROMMP(mp1) == 0)?
    573                                                SDL_WINDOWEVENT_HIDDEN :
    574                                                SDL_WINDOWEVENT_SHOWN   ,
    575                             0, 0);
    576         break;
    577 
    578     case WM_UPDATEFRAME:
    579         /* Return TRUE - no further action for the frame control window procedure */
    580         return (MRESULT)TRUE;
    581 
    582     case WM_ACTIVATE:
    583         if ((BOOL)mp1) {
    584             POINTL  pointl;
    585 
    586             if (SDL_GetKeyboardFocus() != pWinData->window)
    587                 SDL_SetKeyboardFocus(pWinData->window);
    588 
    589             WinQueryPointerPos(HWND_DESKTOP, &pointl);
    590             WinMapWindowPoints(HWND_DESKTOP, pWinData->hwnd, &pointl, 1);
    591             SDL_SendMouseMotion(pWinData->window, 0, 0,
    592                                     pointl.x, pWinData->window->h - pointl.y - 1);
    593         } else {
    594             if (SDL_GetKeyboardFocus() == pWinData->window)
    595                 SDL_SetKeyboardFocus(NULL);
    596 
    597             WinSetCapture(HWND_DESKTOP,  NULLHANDLE);
    598         }
    599         break;
    600 
    601     case WM_MOUSEMOVE:
    602         WinSetPointer(HWND_DESKTOP, hptrCursor);
    603 
    604         if (pWinData->lSkipWMMouseMove > 0)
    605             pWinData->lSkipWMMouseMove--;
    606         else {
    607             _wmMouseMove(pWinData, SHORT1FROMMP(mp1), SHORT2FROMMP(mp1));
    608         }
    609         return (MRESULT)FALSE;
    610 
    611     case WM_BUTTON1DOWN:
    612     case WM_BUTTON1DBLCLK:
    613         _wmMouseButton(pWinData, 0, TRUE);
    614         break;
    615 
    616     case WM_BUTTON1UP:
    617         _wmMouseButton(pWinData, 0, FALSE);
    618         break;
    619 
    620     case WM_BUTTON2DOWN:
    621     case WM_BUTTON2DBLCLK:
    622         _wmMouseButton(pWinData, 1, TRUE);
    623         break;
    624 
    625     case WM_BUTTON2UP:
    626         _wmMouseButton(pWinData, 1, FALSE);
    627         break;
    628 
    629     case WM_BUTTON3DOWN:
    630     case WM_BUTTON3DBLCLK:
    631         _wmMouseButton(pWinData, 2, TRUE);
    632         break;
    633 
    634     case WM_BUTTON3UP:
    635         _wmMouseButton(pWinData, 2, FALSE);
    636         break;
    637 
    638     case WM_TRANSLATEACCEL:
    639         /* ALT and acceleration keys not allowed (must be processed in WM_CHAR) */
    640         if (mp1 == NULL || ((PQMSG)mp1)->msg != WM_CHAR)
    641             break;
    642         return (MRESULT)FALSE;
    643 
    644     case WM_CHAR:
    645         _wmChar(pWinData, mp1, mp2);
    646         break;
    647 
    648     case WM_SIZE:
    649         if (pWinData->lSkipWMSize > 0)
    650             pWinData->lSkipWMSize--;
    651         else {
    652             if ((pWinData->window->flags & SDL_WINDOW_FULLSCREEN) == 0) {
    653                 SDL_SendWindowEvent(pWinData->window, SDL_WINDOWEVENT_RESIZED,
    654                                     SHORT1FROMMP(mp2), SHORT2FROMMP(mp2));
    655             } else {
    656                 pWinData->lSkipWMVRNEnabled++;
    657             }
    658         }
    659         break;
    660 
    661     case WM_MOVE:
    662         if (pWinData->lSkipWMMove > 0)
    663             pWinData->lSkipWMMove--;
    664         else if ((pWinData->window->flags & SDL_WINDOW_FULLSCREEN) == 0) {
    665             _wmMove(pWinData);
    666         }
    667         break;
    668 
    669     case WM_VRNENABLED:
    670         if (pWinData->lSkipWMVRNEnabled > 0)
    671             pWinData->lSkipWMVRNEnabled--;
    672         else {
    673             _setVisibleRegion(pWinData, TRUE);
    674         }
    675         return (MRESULT)TRUE;
    676 
    677     case WM_VRNDISABLED:
    678         _setVisibleRegion(pWinData, FALSE);
    679         return (MRESULT)TRUE;
    680 
    681     case DM_DRAGOVER:
    682         return _wmDragOver(pWinData, (PDRAGINFO)PVOIDFROMMP(mp1));
    683 
    684     case DM_DROP:
    685         return _wmDrop(pWinData, (PDRAGINFO)PVOIDFROMMP(mp1));
    686     }
    687 
    688     return (pWinData->fnUserWndProc != NULL)?
    689             pWinData->fnUserWndProc(hwnd, msg, mp1, mp2) :
    690             WinDefWindowProc(hwnd, msg, mp1, mp2);
    691 }
    692 
    693 
    694 /*  SDL routnes.
    695  *  ------------
    696  */
    697 
    698 static void OS2_PumpEvents(_THIS)
    699 {
    700     SDL_VideoData *pVData = (SDL_VideoData *)_this->driverdata;
    701     QMSG  qmsg;
    702 
    703     if (WinPeekMsg(pVData->hab, &qmsg, NULLHANDLE, 0, 0, PM_REMOVE))
    704         WinDispatchMsg(pVData->hab, &qmsg);
    705 }
    706 
    707 static WINDATA *_setupWindow(_THIS, SDL_Window *window, HWND hwndFrame,
    708                              HWND hwnd)
    709 {
    710     SDL_VideoData *pVData = (SDL_VideoData *)_this->driverdata;
    711     WINDATA       *pWinData = SDL_calloc(1, sizeof(WINDATA));
    712 
    713     if (pWinData == NULL) {
    714         SDL_OutOfMemory();
    715         return NULL;
    716      }
    717     pWinData->hwnd = hwnd;
    718     pWinData->hwndFrame = hwndFrame;
    719     pWinData->window = window;
    720     window->driverdata = pWinData;
    721 
    722     WinSetWindowULong(hwnd, 0, (ULONG)pWinData);
    723     pWinData->fnWndFrameProc = WinSubclassWindow(hwndFrame, wndFrameProc);
    724 
    725     pWinData->pOutput = pVData->pOutput;
    726     pWinData->pVOData = pVData->pOutput->Open();
    727 
    728     WinSetVisibleRegionNotify(hwnd, TRUE);
    729 
    730     return pWinData;
    731 }
    732 
    733 static int OS2_CreateWindow(_THIS, SDL_Window *window)
    734 {
    735     RECTL            rectl;
    736     HWND             hwndFrame, hwnd;
    737     SDL_DisplayMode *pSDLDisplayMode = _getDisplayModeForSDLWindow(window);
    738     ULONG            ulFrameFlags = FCF_TASKLIST  | FCF_TITLEBAR | FCF_SYSMENU |
    739                                     FCF_MINBUTTON | FCF_SHELLPOSITION;
    740     ULONG            ulSWPFlags   = SWP_SIZE | SWP_SHOW | SWP_ZORDER | SWP_ACTIVATE;
    741     WINDATA         *pWinData;
    742 
    743     if (pSDLDisplayMode == NULL)
    744         return -1;
    745 
    746     /* Create a PM window */
    747     if ((window->flags & SDL_WINDOW_RESIZABLE) != 0)
    748         ulFrameFlags |= FCF_SIZEBORDER | FCF_DLGBORDER | FCF_MAXBUTTON;
    749     else if ((window->flags & SDL_WINDOW_BORDERLESS) == 0)
    750         ulFrameFlags |= FCF_DLGBORDER;
    751 
    752     if ((window->flags & SDL_WINDOW_MAXIMIZED) != 0)
    753         ulSWPFlags |= SWP_MAXIMIZE;
    754     else if ((window->flags & SDL_WINDOW_MINIMIZED) != 0)
    755         ulSWPFlags |= SWP_MINIMIZE;
    756 
    757     hwndFrame = WinCreateStdWindow(HWND_DESKTOP, 0, &ulFrameFlags,
    758                                    WIN_CLIENT_CLASS, "SDL2", 0, 0, 0, &hwnd);
    759     if (hwndFrame == NULLHANDLE)
    760         return SDL_SetError("Couldn't create window");
    761 
    762     /* Setup window data and frame window procedure */
    763     pWinData = _setupWindow(_this, window, hwndFrame, hwnd);
    764     if (pWinData == NULL) {
    765         WinDestroyWindow(hwndFrame);
    766         return -1;
    767     }
    768 
    769     /* Show window */
    770     rectl.xLeft   = 0;
    771     rectl.yBottom = 0;
    772     rectl.xRight  = window->w;
    773     rectl.yTop    = window->h;
    774     WinCalcFrameRect(hwndFrame, &rectl, FALSE);
    775     pWinData->lSkipWMSize++;
    776     pWinData->lSkipWMMove++;
    777     WinSetWindowPos(hwndFrame, HWND_TOP, rectl.xLeft, rectl.yBottom,
    778                     rectl.xRight - rectl.xLeft, rectl.yTop - rectl.yBottom,
    779                     ulSWPFlags);
    780 
    781     rectl.xLeft   = 0;
    782     rectl.yBottom = 0;
    783     WinMapWindowPoints(hwnd, HWND_DESKTOP, (PPOINTL)&rectl, 1);
    784     window->x = rectl.xLeft;
    785     window->y = pSDLDisplayMode->h - (rectl.yBottom + window->h);
    786 
    787     window->flags |= SDL_WINDOW_SHOWN;
    788 
    789     return 0;
    790 }
    791 
    792 static int OS2_CreateWindowFrom(_THIS, SDL_Window *window, const void *data)
    793 {
    794     SDL_VideoData   *pVData = (SDL_VideoData *)_this->driverdata;
    795     CHAR             acBuf[256];
    796     CLASSINFO        stCI;
    797     HWND             hwndUser = (HWND)data;
    798     HWND             hwndFrame, hwnd;
    799     ULONG            cbText;
    800     PSZ              pszText;
    801     WINDATA         *pWinData;
    802     SDL_DisplayMode *pSDLDisplayMode = _getDisplayModeForSDLWindow(window);
    803     SWP              swp;
    804     POINTL           pointl;
    805 
    806     debug_os2("Enter");
    807     if (pSDLDisplayMode == NULL)
    808         return -1;
    809 
    810     /* User can accept client OR frame window handle.
    811      * Get client and frame window handles. */
    812     WinQueryClassName(hwndUser, sizeof(acBuf), acBuf);
    813     if (!WinQueryClassInfo(pVData->hab, acBuf, &stCI))
    814         return SDL_SetError("Cannot get user window class information");
    815 
    816     if ((stCI.flClassStyle & CS_FRAME) == 0) {
    817         /* Client window handle is specified */
    818         hwndFrame = WinQueryWindow(hwndUser, QW_PARENT);
    819         if (hwndFrame == NULLHANDLE)
    820             return SDL_SetError("Cannot get parent window handle");
    821 
    822         if ((ULONG)WinSendMsg(hwndFrame, WM_QUERYFRAMEINFO, 0, 0) == 0)
    823             return SDL_SetError("Parent window is not a frame window");
    824 
    825         hwnd = hwndUser;
    826     } else {
    827         /* Frame window handle is specified */
    828         hwnd = WinWindowFromID(hwndUser, FID_CLIENT);
    829         if (hwnd == NULLHANDLE)
    830             return SDL_SetError("Cannot get client window handle");
    831 
    832         hwndFrame = hwndUser;
    833 
    834         WinQueryClassName(hwnd, sizeof(acBuf), acBuf);
    835         if (!WinQueryClassInfo(pVData->hab, acBuf, &stCI))
    836             return SDL_SetError("Cannot get client window class information");
    837     }
    838 
    839     /* Check window's reserved storage */
    840     if (stCI.cbWindowData < sizeof(ULONG))
    841         return SDL_SetError("Reserved storage of window must be at least %u bytes", sizeof(ULONG));
    842 
    843     /* Set SDL-window title */
    844     cbText = WinQueryWindowTextLength(hwndFrame);
    845     pszText = SDL_stack_alloc(CHAR, cbText + 1);
    846 
    847     if (pszText != NULL)
    848         cbText = (pszText != NULL)? WinQueryWindowText(hwndFrame, cbText, pszText) : 0;
    849 
    850     if (cbText != 0)
    851         window->title = OS2_SysToUTF8(pszText);
    852 
    853     if (pszText != NULL)
    854         SDL_stack_free(pszText);
    855 
    856     /* Set SDL-window flags */
    857     window->flags &= ~(SDL_WINDOW_SHOWN     | SDL_WINDOW_BORDERLESS |
    858                        SDL_WINDOW_RESIZABLE | SDL_WINDOW_MAXIMIZED  |
    859                        SDL_WINDOW_MINIMIZED | SDL_WINDOW_INPUT_FOCUS);
    860 
    861     if (WinIsWindowVisible(hwnd))
    862         window->flags |= SDL_WINDOW_SHOWN;
    863 
    864     WinSendMsg(hwndFrame, WM_QUERYBORDERSIZE, MPFROMP(&pointl), 0);
    865     if (pointl.y == WinQuerySysValue(HWND_DESKTOP, SV_CYSIZEBORDER))
    866         window->flags |= SDL_WINDOW_RESIZABLE;
    867     else if (pointl.y <= WinQuerySysValue(HWND_DESKTOP, SV_CYBORDER))
    868         window->flags |= SDL_WINDOW_BORDERLESS;
    869 
    870     WinQueryWindowPos(hwndFrame, &swp);
    871 
    872     if ((swp.fl & SWP_MAXIMIZE) != 0)
    873         window->flags |= SDL_WINDOW_MAXIMIZED;
    874     if ((swp.fl & SWP_MINIMIZE) != 0)
    875         window->flags |= SDL_WINDOW_MINIMIZED;
    876 
    877     pointl.x = 0;
    878     pointl.y = 0;
    879     WinMapWindowPoints(hwnd, HWND_DESKTOP, &pointl, 1);
    880     window->x = pointl.x;
    881     window->y = pSDLDisplayMode->h - (pointl.y + swp.cy);
    882 
    883     WinQueryWindowPos(hwnd, &swp);
    884     window->w = swp.cx;
    885     window->h = swp.cy;
    886 
    887     /* Setup window data and frame window procedure */
    888     pWinData = _setupWindow(_this, window, hwndFrame, hwnd);
    889     if (pWinData == NULL) {
    890         SDL_free(window->title);
    891         window->title = NULL;
    892         return -1;
    893     }
    894     pWinData->fnUserWndProc = WinSubclassWindow(hwnd, wndProc);
    895 
    896     if (WinQueryActiveWindow(HWND_DESKTOP) == hwndFrame)
    897         SDL_SetKeyboardFocus(window);
    898 
    899     return 0;
    900 }
    901 
    902 static void OS2_DestroyWindow(_THIS, SDL_Window * window)
    903 {
    904     SDL_VideoData *pVData = (SDL_VideoData *)_this->driverdata;
    905     WINDATA       *pWinData = (WINDATA *)window->driverdata;
    906 
    907     debug_os2("Enter");
    908     if (pWinData == NULL)
    909         return;
    910 
    911     if (pWinData->fnUserWndProc == NULL) {
    912         /* Window was created by SDL (OS2_CreateWindow()),
    913          * not by user (OS2_CreateWindowFrom()) */
    914         WinDestroyWindow(pWinData->hwndFrame);
    915     } else {
    916         WinSetWindowULong(pWinData->hwnd, 0, 0);
    917     }
    918 
    919     if ((pVData != NULL) && (pWinData->pVOData != NULL)) {
    920         pVData->pOutput->Close(pWinData->pVOData);
    921         pWinData->pVOData = NULL;
    922     }
    923 
    924     if (pWinData->hptrIcon != NULLHANDLE) {
    925         WinDestroyPointer(pWinData->hptrIcon);
    926         pWinData->hptrIcon = NULLHANDLE;
    927     }
    928 
    929     SDL_free(pWinData);
    930     window->driverdata = NULL;
    931 }
    932 
    933 static void OS2_SetWindowTitle(_THIS, SDL_Window *window)
    934 {
    935     PSZ pszTitle = (window->title == NULL)? NULL : OS2_UTF8ToSys(window->title);
    936 
    937     WinSetWindowText(((WINDATA *)window->driverdata)->hwndFrame, pszTitle);
    938     SDL_free(pszTitle);
    939 }
    940 
    941 static void OS2_SetWindowIcon(_THIS, SDL_Window *window, SDL_Surface *icon)
    942 {
    943     WINDATA  *pWinData = (WINDATA *)window->driverdata;
    944     HPOINTER  hptr = utilCreatePointer(icon, 0, 0);
    945 
    946     if (hptr == NULLHANDLE)
    947         return;
    948 
    949     /* Destroy old icon */
    950     if (pWinData->hptrIcon != NULLHANDLE)
    951         WinDestroyPointer(pWinData->hptrIcon);
    952 
    953     /* Set new window icon */
    954     pWinData->hptrIcon = hptr;
    955     if (!WinSendMsg(pWinData->hwndFrame, WM_SETICON, MPFROMLONG(hptr), 0)) {
    956         debug_os2("Cannot set icon for the window");
    957     }
    958 }
    959 
    960 static void OS2_SetWindowPosition(_THIS, SDL_Window *window)
    961 {
    962     WINDATA         *pWinData = (WINDATA *)window->driverdata;
    963     RECTL            rectl;
    964     ULONG            ulFlags;
    965     SDL_DisplayMode *pSDLDisplayMode = _getDisplayModeForSDLWindow(window);
    966 
    967     debug_os2("Enter");
    968     if (pSDLDisplayMode == NULL)
    969         return;
    970 
    971     rectl.xLeft = 0;
    972     rectl.yBottom = 0;
    973     rectl.xRight = window->w;
    974     rectl.yTop = window->h;
    975     WinCalcFrameRect(pWinData->hwndFrame, &rectl, FALSE);
    976 
    977     if (SDL_ShouldAllowTopmost() &&
    978         (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) ==
    979                          (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS) )
    980         ulFlags = SWP_ZORDER | SWP_MOVE | SWP_SIZE;
    981     else
    982         ulFlags = SWP_MOVE | SWP_SIZE;
    983 
    984     pWinData->lSkipWMSize++;
    985     pWinData->lSkipWMMove++;
    986     WinSetWindowPos(pWinData->hwndFrame, HWND_TOP,
    987                     window->x + rectl.xLeft,
    988                     (pSDLDisplayMode->h - window->y) - window->h + rectl.yBottom,
    989                     rectl.xRight - rectl.xLeft, rectl.yTop - rectl.yBottom,
    990                     ulFlags);
    991 }
    992 
    993 static void OS2_SetWindowSize(_THIS, SDL_Window *window)
    994 {
    995     debug_os2("Enter");
    996     OS2_SetWindowPosition(_this, window);
    997 }
    998 
    999 static void OS2_ShowWindow(_THIS, SDL_Window *window)
   1000 {
   1001     WINDATA *pWinData = (WINDATA *)window->driverdata;
   1002 
   1003     debug_os2("Enter");
   1004     WinShowWindow(pWinData->hwndFrame, TRUE);
   1005 }
   1006 
   1007 static void OS2_HideWindow(_THIS, SDL_Window *window)
   1008 {
   1009     WINDATA *pWinData = (WINDATA *)window->driverdata;
   1010 
   1011     debug_os2("Enter");
   1012     WinShowWindow(pWinData->hwndFrame, FALSE);
   1013 }
   1014 
   1015 static void OS2_RaiseWindow(_THIS, SDL_Window *window)
   1016 {
   1017     debug_os2("Enter");
   1018     OS2_SetWindowPosition(_this, window);
   1019 }
   1020 
   1021 static void OS2_MaximizeWindow(_THIS, SDL_Window *window)
   1022 {
   1023     WINDATA *pWinData = (WINDATA *)window->driverdata;
   1024 
   1025     debug_os2("Enter");
   1026     WinSetWindowPos(pWinData->hwndFrame, HWND_TOP, 0, 0, 0, 0, SWP_MAXIMIZE);
   1027 }
   1028 
   1029 static void OS2_MinimizeWindow(_THIS, SDL_Window *window)
   1030 {
   1031     WINDATA *pWinData = (WINDATA *)window->driverdata;
   1032 
   1033     debug_os2("Enter");
   1034     WinSetWindowPos(pWinData->hwndFrame, HWND_TOP, 0, 0, 0, 0, SWP_MINIMIZE | SWP_DEACTIVATE);
   1035 }
   1036 
   1037 static void OS2_RestoreWindow(_THIS, SDL_Window *window)
   1038 {
   1039     WINDATA *pWinData = (WINDATA *)window->driverdata;
   1040 
   1041     debug_os2("Enter");
   1042     WinSetWindowPos(pWinData->hwndFrame, HWND_TOP, 0, 0, 0, 0, SWP_RESTORE);
   1043 }
   1044 
   1045 static void OS2_SetWindowBordered(_THIS, SDL_Window * window,
   1046                                   SDL_bool bordered)
   1047 {
   1048     WINDATA *pWinData = (WINDATA *)window->driverdata;
   1049     ULONG    ulStyle = WinQueryWindowULong(pWinData->hwndFrame, QWL_STYLE);
   1050     RECTL    rectl;
   1051 
   1052     debug_os2("Enter");
   1053 
   1054     /* New frame sytle */
   1055     if (bordered)
   1056         ulStyle |= ((window->flags & SDL_WINDOW_RESIZABLE) != 0) ? FS_SIZEBORDER : FS_DLGBORDER;
   1057     else
   1058         ulStyle &= ~(FS_SIZEBORDER | FS_BORDER | FS_DLGBORDER);
   1059 
   1060     /* Save client window position */
   1061     WinQueryWindowRect(pWinData->hwnd, &rectl);
   1062     WinMapWindowPoints(pWinData->hwnd, HWND_DESKTOP, (PPOINTL)&rectl, 2);
   1063 
   1064     /* Change the frame */
   1065     WinSetWindowULong(pWinData->hwndFrame, QWL_STYLE, ulStyle);
   1066     WinSendMsg(pWinData->hwndFrame, WM_UPDATEFRAME, MPFROMLONG(FCF_BORDER), 0);
   1067 
   1068     /* Restore client window position */
   1069     WinCalcFrameRect(pWinData->hwndFrame, &rectl, FALSE);
   1070     pWinData->lSkipWMMove++;
   1071     WinSetWindowPos(pWinData->hwndFrame, HWND_TOP, rectl.xLeft, rectl.yBottom,
   1072                     rectl.xRight - rectl.xLeft,
   1073                     rectl.yTop - rectl.yBottom,
   1074                     SWP_SIZE | SWP_MOVE | SWP_NOADJUST);
   1075 }
   1076 
   1077 static void OS2_SetWindowFullscreen(_THIS, SDL_Window *window,
   1078                                     SDL_VideoDisplay *display,
   1079                                     SDL_bool fullscreen)
   1080 {
   1081     RECTL            rectl;
   1082     ULONG            ulFlags;
   1083     WINDATA         *pWinData = (WINDATA *)window->driverdata;
   1084     SDL_DisplayMode *pSDLDisplayMode = &display->current_mode;
   1085 
   1086     debug_os2("Enter, fullscreen: %u", fullscreen);
   1087 
   1088     if (pSDLDisplayMode == NULL)
   1089         return;
   1090 
   1091     if (SDL_ShouldAllowTopmost() &&
   1092         (window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS))
   1093         ulFlags = SWP_SIZE | SWP_MOVE | SWP_ZORDER | SWP_NOADJUST;
   1094     else
   1095         ulFlags = SWP_SIZE | SWP_MOVE | SWP_NOADJUST;
   1096 
   1097     if (fullscreen) {
   1098         rectl.xLeft = 0;
   1099         rectl.yBottom = 0;
   1100         rectl.xRight = pSDLDisplayMode->w;
   1101         rectl.yTop = pSDLDisplayMode->h;
   1102         /* We need send the restore command now to allow WinCalcFrameRect() */
   1103         WinSetWindowPos(pWinData->hwndFrame, HWND_TOP, 0, 0, 0, 0, SWP_RESTORE);
   1104     } else {
   1105         pWinData->lSkipWMMove++;
   1106         rectl.xLeft = window->windowed.x;
   1107         rectl.yTop = pSDLDisplayMode->h - window->windowed.y;
   1108         rectl.xRight = rectl.xLeft + window->windowed.w;
   1109         rectl.yBottom = rectl.yTop - window->windowed.h;
   1110     }
   1111 
   1112     if (!WinCalcFrameRect(pWinData->hwndFrame, &rectl, FALSE)) {
   1113         debug_os2("WinCalcFrameRect() failed");
   1114     }
   1115     else if (!WinSetWindowPos(pWinData->hwndFrame, HWND_TOP,
   1116                               rectl.xLeft, rectl.yBottom,
   1117                               rectl.xRight - rectl.xLeft, rectl.yTop - rectl.yBottom,
   1118                               ulFlags)) {
   1119         debug_os2("WinSetWindowPos() failed");
   1120     }
   1121 }
   1122 
   1123 static SDL_bool OS2_GetWindowWMInfo(_THIS, SDL_Window * window,
   1124                                     struct SDL_SysWMinfo *info)
   1125 {
   1126     WINDATA *pWinData = (WINDATA *)window->driverdata;
   1127 
   1128     if (info->version.major <= SDL_MAJOR_VERSION) {
   1129         info->subsystem = SDL_SYSWM_OS2;
   1130         info->info.os2.hwnd = pWinData->hwnd;
   1131         info->info.os2.hwndFrame = pWinData->hwndFrame;
   1132         return SDL_TRUE;
   1133     }
   1134 
   1135     SDL_SetError("Application not compiled with SDL %u.%u",
   1136                  SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
   1137     return SDL_FALSE;
   1138 }
   1139 
   1140 static void OS2_OnWindowEnter(_THIS, SDL_Window * window)
   1141 {
   1142 }
   1143 
   1144 static int OS2_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
   1145 {
   1146   debug_os2("Enter");
   1147   return 0;
   1148 }
   1149 
   1150 static void OS2_SetWindowGrab(_THIS, SDL_Window *window, SDL_bool grabbed)
   1151 {
   1152     WINDATA *pWinData = (WINDATA *)window->driverdata;
   1153 
   1154     debug_os2("Enter, %u", grabbed);
   1155     _mouseCheck(pWinData);
   1156 }
   1157 
   1158 
   1159 /* Shaper
   1160  */
   1161 typedef struct _SHAPERECTS {
   1162   PRECTL     pRects;
   1163   ULONG      cRects;
   1164   ULONG      ulWinHeight;
   1165 } SHAPERECTS;
   1166 
   1167 static void _combineRectRegions(SDL_ShapeTree *node, void *closure)
   1168 {
   1169     SHAPERECTS *pShapeRects = (SHAPERECTS *)closure;
   1170     PRECTL      pRect;
   1171 
   1172     /* Expand rectangles list */
   1173     if ((pShapeRects->cRects & 0x0F) == 0) {
   1174         pRect = SDL_realloc(pShapeRects->pRects, (pShapeRects->cRects + 0x10) * sizeof(RECTL));
   1175         if (pRect == NULL)
   1176             return;
   1177         pShapeRects->pRects = pRect;
   1178     }
   1179 
   1180     /* Add a new rectangle */
   1181     pRect = &pShapeRects->pRects[pShapeRects->cRects];
   1182     pShapeRects->cRects++;
   1183     /* Fill rectangle data */
   1184     pRect->xLeft = node->data.shape.x;
   1185     pRect->yTop = pShapeRects->ulWinHeight - node->data.shape.y;
   1186     pRect->xRight += node->data.shape.w;
   1187     pRect->yBottom = pRect->yTop - node->data.shape.h;
   1188 }
   1189 
   1190 static SDL_WindowShaper* OS2_CreateShaper(SDL_Window * window)
   1191 {
   1192     SDL_WindowShaper* pSDLShaper = SDL_malloc(sizeof(SDL_WindowShaper));
   1193 
   1194     debug_os2("Enter");
   1195     pSDLShaper->window = window;
   1196     pSDLShaper->mode.mode = ShapeModeDefault;
   1197     pSDLShaper->mode.parameters.binarizationCutoff = 1;
   1198     pSDLShaper->userx = 0;
   1199     pSDLShaper->usery = 0;
   1200     pSDLShaper->driverdata = (SDL_ShapeTree *)NULL;
   1201     window->shaper = pSDLShaper;
   1202 
   1203     if (OS2_ResizeWindowShape(window) != 0) {
   1204         window->shaper = NULL;
   1205         SDL_free(pSDLShaper);
   1206         return NULL;
   1207     }
   1208 
   1209     return pSDLShaper;
   1210 }
   1211 
   1212 static int OS2_SetWindowShape(SDL_WindowShaper *shaper, SDL_Surface *shape,
   1213                               SDL_WindowShapeMode *shape_mode)
   1214 {
   1215     SDL_ShapeTree *pShapeTree;
   1216     WINDATA       *pWinData;
   1217     SHAPERECTS     stShapeRects = { 0 };
   1218     HPS            hps;
   1219 
   1220     debug_os2("Enter");
   1221     if (shaper == NULL || shape == NULL ||
   1222         (shape->format->Amask == 0 && shape_mode->mode != ShapeModeColorKey) ||
   1223         shape->w != shaper->window->w || shape->h != shaper->window->h) {
   1224         return SDL_INVALID_SHAPE_ARGUMENT;
   1225     }
   1226 
   1227     if (shaper->driverdata != NULL)
   1228         SDL_FreeShapeTree((SDL_ShapeTree **)&shaper->driverdata);
   1229 
   1230     pShapeTree = SDL_CalculateShapeTree(*shape_mode, shape);
   1231     shaper->driverdata = pShapeTree;
   1232 
   1233     stShapeRects.ulWinHeight = shaper->window->h;
   1234     SDL_TraverseShapeTree(pShapeTree, &_combineRectRegions, &stShapeRects);
   1235 
   1236     pWinData = (WINDATA *)shaper->window->driverdata;
   1237     hps = WinGetPS(pWinData->hwnd);
   1238 
   1239     if (pWinData->hrgnShape != NULLHANDLE)
   1240         GpiDestroyRegion(hps, pWinData->hrgnShape);
   1241 
   1242     pWinData->hrgnShape = (stShapeRects.pRects == NULL) ? NULLHANDLE :
   1243                                 GpiCreateRegion(hps, stShapeRects.cRects, stShapeRects.pRects);
   1244 
   1245     WinReleasePS(hps);
   1246     SDL_free(stShapeRects.pRects);
   1247     WinSendMsg(pWinData->hwnd, WM_VRNENABLED, 0, 0);
   1248 
   1249     return 0;
   1250 }
   1251 
   1252 static int OS2_ResizeWindowShape(SDL_Window *window)
   1253 {
   1254     debug_os2("Enter");
   1255     if (window == NULL)
   1256         return -1;
   1257 
   1258     if (window->x != -1000) {
   1259         if (window->shaper->driverdata != NULL)
   1260             SDL_FreeShapeTree((SDL_ShapeTree **)window->shaper->driverdata);
   1261 
   1262         if (window->shaper->hasshape == SDL_TRUE) {
   1263             window->shaper->userx = window->x;
   1264             window->shaper->usery = window->y;
   1265             SDL_SetWindowPosition(window, -1000, -1000);
   1266         }
   1267     }
   1268 
   1269     return 0;
   1270 }
   1271 
   1272 
   1273 /* Frame buffer
   1274  */
   1275 static void OS2_DestroyWindowFramebuffer(_THIS, SDL_Window *window)
   1276 {
   1277     WINDATA *pWinData = (WINDATA *)window->driverdata;
   1278 
   1279     debug_os2("Enter");
   1280     if (pWinData != NULL && pWinData->pVOData != NULL)
   1281         pWinData->pOutput->VideoBufFree(pWinData->pVOData);
   1282 }
   1283 
   1284 static int OS2_CreateWindowFramebuffer(_THIS, SDL_Window *window,
   1285                                        Uint32 *format, void **pixels,
   1286                                        int *pitch)
   1287 {
   1288     WINDATA          *pWinData = (WINDATA *)window->driverdata;
   1289     SDL_VideoDisplay *pSDLDisplay = SDL_GetDisplayForWindow(window);
   1290     SDL_DisplayMode  *pSDLDisplayMode;
   1291     MODEDATA         *pModeData;
   1292     ULONG             ulWidth, ulHeight;
   1293 
   1294     debug_os2("Enter");
   1295     if (pSDLDisplay == NULL) {
   1296         debug_os2("No display for the window");
   1297         return -1;
   1298     }
   1299 
   1300     pSDLDisplayMode = &pSDLDisplay->current_mode;
   1301     pModeData = (MODEDATA *)pSDLDisplayMode->driverdata;
   1302     if (pModeData == NULL)
   1303         return SDL_SetError("No mode data for the display");
   1304 
   1305     SDL_GetWindowSize(window, (int *)&ulWidth, (int *)&ulHeight);
   1306     debug_os2("Window size: %u x %u", ulWidth, ulHeight);
   1307 
   1308     *pixels = pWinData->pOutput->VideoBufAlloc(
   1309                         pWinData->pVOData, ulWidth, ulHeight, pModeData->ulDepth,
   1310                         pModeData->fccColorEncoding, (PULONG)pitch);
   1311     if (*pixels == NULL)
   1312         return -1;
   1313 
   1314     *format = pSDLDisplayMode->format;
   1315     debug_os2("Pitch: %u, frame buffer: 0x%X.", *pitch, *pixels);
   1316     WinSendMsg(pWinData->hwnd, WM_VRNENABLED, 0, 0);
   1317 
   1318     return 0;
   1319 }
   1320 
   1321 static int OS2_UpdateWindowFramebuffer(_THIS, SDL_Window * window,
   1322                                        const SDL_Rect *rects, int numrects)
   1323 {
   1324     WINDATA *pWinData = (WINDATA *)window->driverdata;
   1325 
   1326     return pWinData->pOutput->Update(pWinData->pVOData, pWinData->hwnd,
   1327                                      (SDL_Rect *)rects, (ULONG)numrects)
   1328            ? 0 : -1;
   1329 }
   1330 
   1331 
   1332 /* Clipboard
   1333  */
   1334 static int OS2_SetClipboardText(_THIS, const char *text)
   1335 {
   1336     SDL_VideoData *pVData = (SDL_VideoData *)_this->driverdata;
   1337     PSZ   pszClipboard;
   1338     PSZ   pszText = (text == NULL)? NULL : OS2_UTF8ToSys(text);
   1339     ULONG cbText;
   1340     ULONG ulRC;
   1341     BOOL  fSuccess;
   1342 
   1343     debug_os2("Enter");
   1344     if (pszText == NULL)
   1345         return -1;
   1346     cbText = SDL_strlen(pszText);
   1347 
   1348     ulRC = DosAllocSharedMem((PPVOID)&pszClipboard, 0, cbText + 1,
   1349                               PAG_COMMIT | PAG_READ | PAG_WRITE |
   1350                               OBJ_GIVEABLE | OBJ_GETTABLE | OBJ_TILE);
   1351     if (ulRC != NO_ERROR) {
   1352         debug_os2("DosAllocSharedMem() failed, rc = %u", ulRC);
   1353         SDL_free(pszText);
   1354         return -1;
   1355     }
   1356 
   1357     strcpy(pszClipboard, pszText);
   1358     SDL_free(pszText);
   1359 
   1360     if (!WinOpenClipbrd(pVData->hab)) {
   1361         debug_os2("WinOpenClipbrd() failed");
   1362         fSuccess = FALSE;
   1363     } else {
   1364         WinEmptyClipbrd(pVData->hab);
   1365         fSuccess = WinSetClipbrdData(pVData->hab, (ULONG)pszClipboard, CF_TEXT, CFI_POINTER);
   1366         if (!fSuccess) {
   1367             debug_os2("WinOpenClipbrd() failed");
   1368         }
   1369         WinCloseClipbrd(pVData->hab);
   1370     }
   1371 
   1372     if (!fSuccess) {
   1373         DosFreeMem(pszClipboard);
   1374         return -1;
   1375     }
   1376     return 0;
   1377 }
   1378 
   1379 static char *OS2_GetClipboardText(_THIS)
   1380 {
   1381     SDL_VideoData *pVData = (SDL_VideoData *)_this->driverdata;
   1382     PSZ pszClipboard = NULL;
   1383 
   1384     if (!WinOpenClipbrd(pVData->hab)) {
   1385         debug_os2("WinOpenClipbrd() failed");
   1386     } else {
   1387         pszClipboard = (PSZ)WinQueryClipbrdData(pVData->hab, CF_TEXT);
   1388         if (pszClipboard != NULL)
   1389             pszClipboard = OS2_SysToUTF8(pszClipboard);
   1390         WinCloseClipbrd(pVData->hab);
   1391     }
   1392 
   1393     return (pszClipboard == NULL) ? SDL_strdup("") : pszClipboard;
   1394 }
   1395 
   1396 static SDL_bool OS2_HasClipboardText(_THIS)
   1397 {
   1398     SDL_VideoData *pVData = (SDL_VideoData *)_this->driverdata;
   1399     SDL_bool   fClipboard;
   1400 
   1401     if (!WinOpenClipbrd(pVData->hab)) {
   1402         debug_os2("WinOpenClipbrd() failed");
   1403         return SDL_FALSE;
   1404     }
   1405 
   1406     fClipboard = ((PSZ)WinQueryClipbrdData(pVData->hab, CF_TEXT) != NULL)?
   1407                    SDL_TRUE : SDL_FALSE;
   1408     WinCloseClipbrd(pVData->hab);
   1409 
   1410     return fClipboard;
   1411 }
   1412 
   1413 
   1414 static int OS2_VideoInit(_THIS)
   1415 {
   1416     SDL_VideoData *pVData;
   1417     PTIB  tib;
   1418     PPIB  pib;
   1419 
   1420     /* Create SDL video driver private data */
   1421     pVData = SDL_calloc(1, sizeof(SDL_VideoData));
   1422     if (pVData == NULL)
   1423         return SDL_OutOfMemory();
   1424 
   1425     /* Change process type code for use Win* API from VIO session */
   1426     DosGetInfoBlocks(&tib, &pib);
   1427     if (pib->pib_ultype == 2 || pib->pib_ultype == 0) {
   1428         /* VIO windowable or fullscreen protect-mode session */
   1429         pib->pib_ultype = 3; /* Presentation Manager protect-mode session */
   1430     }
   1431 
   1432     /* PM initialization */
   1433     pVData->hab = WinInitialize(0);
   1434     pVData->hmq = WinCreateMsgQueue(pVData->hab, 0);
   1435     if (pVData->hmq == NULLHANDLE) {
   1436         SDL_free(pVData);
   1437         return SDL_SetError("Message queue cannot be created.");
   1438     }
   1439 
   1440     if (!WinRegisterClass(pVData->hab, WIN_CLIENT_CLASS, wndProc,
   1441                           CS_SIZEREDRAW | CS_MOVENOTIFY | CS_SYNCPAINT,
   1442                           sizeof(SDL_VideoData*))) {
   1443         SDL_free(pVData);
   1444         return SDL_SetError("Window class not successfully registered.");
   1445     }
   1446 
   1447     if (stricmp(_this->name, OS2DRIVER_NAME_VMAN) == 0)
   1448         pVData->pOutput = &voVMan;
   1449     else
   1450         pVData->pOutput = &voDive;
   1451 
   1452     _this->driverdata = pVData;
   1453 
   1454     /* Add display */
   1455     {
   1456         SDL_VideoDisplay    stSDLDisplay;
   1457         SDL_DisplayMode     stSDLDisplayMode;
   1458         DISPLAYDATA        *pDisplayData;
   1459         MODEDATA           *pModeData;
   1460         VIDEOOUTPUTINFO     stVOInfo;
   1461 
   1462         if (!pVData->pOutput->QueryInfo(&stVOInfo)) {
   1463             SDL_free(pVData);
   1464             return SDL_SetError("Video mode query failed.");
   1465         }
   1466 
   1467         SDL_zero(stSDLDisplay); SDL_zero(stSDLDisplayMode);
   1468 
   1469         stSDLDisplayMode.format = _getSDLPixelFormat(stVOInfo.ulBPP,
   1470                                                      stVOInfo.fccColorEncoding);
   1471         stSDLDisplayMode.w = stVOInfo.ulHorizResolution;
   1472         stSDLDisplayMode.h = stVOInfo.ulVertResolution;
   1473         stSDLDisplayMode.refresh_rate = 0;
   1474         stSDLDisplayMode.driverdata = NULL;
   1475 
   1476         pModeData = SDL_malloc(sizeof(MODEDATA));
   1477         if (pModeData != NULL) {
   1478             pModeData->ulDepth = stVOInfo.ulBPP;
   1479             pModeData->fccColorEncoding = stVOInfo.fccColorEncoding;
   1480             pModeData->ulScanLineBytes = stVOInfo.ulScanLineSize;
   1481             stSDLDisplayMode.driverdata = pModeData;
   1482         }
   1483 
   1484         stSDLDisplay.name = "Primary";
   1485         stSDLDisplay.desktop_mode = stSDLDisplayMode;
   1486         stSDLDisplay.current_mode = stSDLDisplayMode;
   1487         stSDLDisplay.driverdata = NULL;
   1488         stSDLDisplay.num_display_modes = 0;
   1489 
   1490         pDisplayData = SDL_malloc(sizeof(DISPLAYDATA));
   1491         if (pDisplayData != NULL) {
   1492             HPS hps = WinGetPS(HWND_DESKTOP);
   1493             HDC hdc = GpiQueryDevice(hps);
   1494 
   1495             /* May be we can use CAPS_HORIZONTAL_RESOLUTION and
   1496              * CAPS_VERTICAL_RESOLUTION - pels per meter?  */
   1497             DevQueryCaps(hdc, CAPS_HORIZONTAL_FONT_RES, 1,
   1498                           (PLONG)&pDisplayData->ulDPIHor);
   1499             DevQueryCaps(hdc, CAPS_VERTICAL_FONT_RES, 1,
   1500                           (PLONG)&pDisplayData->ulDPIVer);
   1501             WinReleasePS(hps);
   1502 
   1503             pDisplayData->ulDPIDiag = SDL_ComputeDiagonalDPI(
   1504                   stVOInfo.ulHorizResolution, stVOInfo.ulVertResolution,
   1505                   (float)stVOInfo.ulHorizResolution / pDisplayData->ulDPIHor,
   1506                   (float)stVOInfo.ulVertResolution / pDisplayData->ulDPIVer);
   1507 
   1508             stSDLDisplayMode.driverdata = pDisplayData;
   1509         }
   1510 
   1511         SDL_AddVideoDisplay(&stSDLDisplay, SDL_FALSE);
   1512     }
   1513 
   1514     OS2_InitMouse(_this, pVData->hab);
   1515 
   1516     return 0;
   1517 }
   1518 
   1519 static void OS2_VideoQuit(_THIS)
   1520 {
   1521     SDL_VideoData *pVData = (SDL_VideoData *)_this->driverdata;
   1522 
   1523     OS2_QuitMouse(_this);
   1524 
   1525     WinDestroyMsgQueue(pVData->hmq);
   1526     WinTerminate(pVData->hab);
   1527 
   1528     /* our caller SDL_VideoQuit() already frees display_modes, driverdata, etc. */
   1529 }
   1530 
   1531 static int OS2_GetDisplayBounds(_THIS, SDL_VideoDisplay *display,
   1532                                 SDL_Rect *rect)
   1533 {
   1534     debug_os2("Enter");
   1535 
   1536     rect->x = 0;
   1537     rect->y = 0;
   1538     rect->w = display->desktop_mode.w;
   1539     rect->h = display->desktop_mode.h;
   1540 
   1541     return 0;
   1542 }
   1543 
   1544 static int OS2_GetDisplayDPI(_THIS, SDL_VideoDisplay *display, float *ddpi,
   1545                              float *hdpi, float *vdpi)
   1546 {
   1547     DISPLAYDATA *pDisplayData = (DISPLAYDATA *)display->driverdata;
   1548 
   1549     debug_os2("Enter");
   1550     if (pDisplayData == NULL)
   1551         return -1;
   1552 
   1553     if (ddpi != NULL)
   1554         *hdpi = pDisplayData->ulDPIDiag;
   1555     if (hdpi != NULL)
   1556         *hdpi = pDisplayData->ulDPIHor;
   1557     if (vdpi != NULL)
   1558         *vdpi = pDisplayData->ulDPIVer;
   1559 
   1560     return 0;
   1561 }
   1562 
   1563 static void OS2_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
   1564 {
   1565     debug_os2("Enter");
   1566     SDL_AddDisplayMode(display, &display->current_mode);
   1567 }
   1568 
   1569 static int OS2_SetDisplayMode(_THIS, SDL_VideoDisplay *display,
   1570                               SDL_DisplayMode *mode)
   1571 {
   1572     debug_os2("Enter");
   1573     return -1;
   1574 }
   1575 
   1576 
   1577 static void OS2_DeleteDevice(SDL_VideoDevice *device)
   1578 {
   1579     SDL_free(device);
   1580 }
   1581 
   1582 static SDL_VideoDevice *OS2_CreateDevice(int devindex)
   1583 {
   1584     SDL_VideoDevice *device;
   1585 
   1586     /* Initialize all variables that we clean on shutdown */
   1587     device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice));
   1588     if (!device) {
   1589         SDL_OutOfMemory();
   1590         return NULL;
   1591     }
   1592 
   1593     /* Set the function pointers */
   1594     device->VideoInit = OS2_VideoInit;
   1595     device->VideoQuit = OS2_VideoQuit;
   1596     device->GetDisplayBounds = OS2_GetDisplayBounds;
   1597     device->GetDisplayDPI = OS2_GetDisplayDPI;
   1598     device->GetDisplayModes = OS2_GetDisplayModes;
   1599     device->SetDisplayMode = OS2_SetDisplayMode;
   1600     device->PumpEvents = OS2_PumpEvents;
   1601     device->CreateSDLWindow = OS2_CreateWindow;
   1602     device->CreateSDLWindowFrom = OS2_CreateWindowFrom;
   1603     device->DestroyWindow = OS2_DestroyWindow;
   1604     device->SetWindowTitle = OS2_SetWindowTitle;
   1605     device->SetWindowIcon = OS2_SetWindowIcon;
   1606     device->SetWindowPosition = OS2_SetWindowPosition;
   1607     device->SetWindowSize = OS2_SetWindowSize;
   1608     device->ShowWindow = OS2_ShowWindow;
   1609     device->HideWindow = OS2_HideWindow;
   1610     device->RaiseWindow = OS2_RaiseWindow;
   1611     device->MaximizeWindow = OS2_MaximizeWindow;
   1612     device->MinimizeWindow = OS2_MinimizeWindow;
   1613     device->RestoreWindow = OS2_RestoreWindow;
   1614     device->SetWindowBordered = OS2_SetWindowBordered;
   1615     device->SetWindowFullscreen = OS2_SetWindowFullscreen;
   1616     device->GetWindowWMInfo = OS2_GetWindowWMInfo;
   1617     device->OnWindowEnter = OS2_OnWindowEnter;
   1618     device->SetWindowHitTest = OS2_SetWindowHitTest;
   1619     device->SetWindowGrab = OS2_SetWindowGrab;
   1620     device->CreateWindowFramebuffer = OS2_CreateWindowFramebuffer;
   1621     device->UpdateWindowFramebuffer = OS2_UpdateWindowFramebuffer;
   1622     device->DestroyWindowFramebuffer = OS2_DestroyWindowFramebuffer;
   1623 
   1624     device->SetClipboardText = OS2_SetClipboardText;
   1625     device->GetClipboardText = OS2_GetClipboardText;
   1626     device->HasClipboardText = OS2_HasClipboardText;
   1627 
   1628     device->shape_driver.CreateShaper = OS2_CreateShaper;
   1629     device->shape_driver.SetWindowShape = OS2_SetWindowShape;
   1630     device->shape_driver.ResizeWindowShape = OS2_ResizeWindowShape;
   1631 
   1632     device->free = OS2_DeleteDevice;
   1633 
   1634     return device;
   1635 }
   1636 
   1637 static SDL_VideoDevice *OS2DIVE_CreateDevice(int devindex)
   1638 {
   1639     VIDEOOUTPUTINFO stVOInfo;
   1640     if (!voDive.QueryInfo(&stVOInfo)) {
   1641         return NULL;
   1642     }
   1643     return OS2_CreateDevice(devindex);
   1644 }
   1645 
   1646 static SDL_VideoDevice *OS2VMAN_CreateDevice(int devindex)
   1647 {
   1648     VIDEOOUTPUTINFO stVOInfo;
   1649     if (!voVMan.QueryInfo(&stVOInfo)) {
   1650           return NULL;
   1651     }
   1652     return OS2_CreateDevice(devindex);
   1653 }
   1654 
   1655 
   1656 /* Both bootstraps for DIVE and VMAN are uing same function OS2_CreateDevice().
   1657  * Video output system will be selected in OS2_VideoInit() by driver name.  */
   1658 VideoBootStrap OS2DIVE_bootstrap =
   1659 {
   1660   OS2DRIVER_NAME_DIVE, "OS/2 video driver",
   1661   OS2DIVE_CreateDevice
   1662 };
   1663 
   1664 VideoBootStrap OS2VMAN_bootstrap =
   1665 {
   1666   OS2DRIVER_NAME_VMAN, "OS/2 video driver",
   1667   OS2VMAN_CreateDevice
   1668 };
   1669 
   1670 #endif /* SDL_VIDEO_DRIVER_OS2 */
   1671 
   1672 /* vi: set ts=4 sw=4 expandtab: */