blob: 0ec0f1e61e110f8cd16032b0b6a19fb2243d4eb6 [file] [log] [blame]
/*
Simple DirectMedia Layer
Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
#include "../../SDL_internal.h"
#if SDL_VIDEO_DRIVER_OS2
#include "SDL_video.h"
#include "SDL_mouse.h"
#include "../SDL_pixels_c.h"
#include "../SDL_shape_internals.h"
#include "../../events/SDL_events_c.h"
#include "SDL_os2video.h"
#include "SDL_syswm.h"
#include "SDL_os2util.h"
#define __MEERROR_H__
#define _MEERROR_H_
#include <mmioos2.h>
#include <fourcc.h>
#ifndef FOURCC_R666
#define FOURCC_R666 mmioFOURCC('R','6','6','6')
#endif
#define WIN_CLIENT_CLASS "SDL2"
#define OS2DRIVER_NAME_DIVE "DIVE"
#define OS2DRIVER_NAME_VMAN "VMAN"
static const SDL_Scancode aSDLScancode[] = {
/* 0 1 2 3 4 5 6 7 */
/* 8 9 A B C D E F */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 */
/*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 */
/*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 */
/*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 */
/*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 */
/*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 */
/*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 */
/*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 */
};
/* Utilites.
* ---------
*/
static BOOL _getSDLPixelFormatData(SDL_PixelFormat *pSDLPixelFormat,
ULONG ulBPP, ULONG fccColorEncoding)
{
ULONG ulRshift, ulGshift, ulBshift;
ULONG ulRmask, ulGmask, ulBmask;
ULONG ulRloss, ulGloss, ulBloss;
pSDLPixelFormat->BitsPerPixel = ulBPP;
pSDLPixelFormat->BytesPerPixel = (pSDLPixelFormat->BitsPerPixel + 7) / 8;
switch (fccColorEncoding) {
case FOURCC_LUT8:
ulRshift = 0; ulGshift = 0; ulBshift = 0;
ulRmask = 0; ulGmask = 0; ulBmask = 0;
ulRloss = 8; ulGloss = 8; ulBloss = 8;
break;
case FOURCC_R555:
ulRshift = 10; ulGshift = 5; ulBshift = 0;
ulRmask = 0x7C00; ulGmask = 0x03E0; ulBmask = 0x001F;
ulRloss = 3; ulGloss = 3; ulBloss = 3;
break;
case FOURCC_R565:
ulRshift = 11; ulGshift = 5; ulBshift = 0;
ulRmask = 0xF800; ulGmask = 0x07E0; ulBmask = 0x001F;
ulRloss = 3; ulGloss = 2; ulBloss = 3;
break;
case FOURCC_R664:
ulRshift = 10; ulGshift = 4; ulBshift = 0;
ulRmask = 0xFC00; ulGmask = 0x03F0; ulBmask = 0x000F;
ulRloss = 2; ulGloss = 4; ulBloss = 3;
break;
case FOURCC_R666:
ulRshift = 12; ulGshift = 6; ulBshift = 0;
ulRmask = 0x03F000; ulGmask = 0x000FC0; ulBmask = 0x00003F;
ulRloss = 2; ulGloss = 2; ulBloss = 2;
break;
case FOURCC_RGB3:
case FOURCC_RGB4:
ulRshift = 0; ulGshift = 8; ulBshift = 16;
ulRmask = 0x0000FF; ulGmask = 0x00FF00; ulBmask = 0xFF0000;
ulRloss = 0x00; ulGloss = 0x00; ulBloss = 0x00;
break;
case FOURCC_BGR3:
case FOURCC_BGR4:
ulRshift = 16; ulGshift = 8; ulBshift = 0;
ulRmask = 0xFF0000; ulGmask = 0x00FF00; ulBmask = 0x0000FF;
ulRloss = 0; ulGloss = 0; ulBloss = 0;
break;
default:
/* printf("Unknown color encoding: %.4s\n", fccColorEncoding);*/
memset(pSDLPixelFormat, 0, sizeof(SDL_PixelFormat));
return FALSE;
}
pSDLPixelFormat->Rshift = ulRshift;
pSDLPixelFormat->Gshift = ulGshift;
pSDLPixelFormat->Bshift = ulBshift;
pSDLPixelFormat->Rmask = ulRmask;
pSDLPixelFormat->Gmask = ulGmask;
pSDLPixelFormat->Bmask = ulBmask;
pSDLPixelFormat->Rloss = ulRloss;
pSDLPixelFormat->Gloss = ulGloss;
pSDLPixelFormat->Bloss = ulBloss;
pSDLPixelFormat->Ashift = 0x00;
pSDLPixelFormat->Amask = 0x00;
pSDLPixelFormat->Aloss = 0x00;
return TRUE;
}
static Uint32 _getSDLPixelFormat(ULONG ulBPP, FOURCC fccColorEncoding)
{
SDL_PixelFormat stSDLPixelFormat;
Uint32 uiResult = SDL_PIXELFORMAT_UNKNOWN;
if (_getSDLPixelFormatData(&stSDLPixelFormat, ulBPP, fccColorEncoding))
uiResult = SDL_MasksToPixelFormatEnum(ulBPP, stSDLPixelFormat.Rmask,
stSDLPixelFormat.Gmask,
stSDLPixelFormat.Bmask, 0);
return uiResult;
}
static SDL_DisplayMode *_getDisplayModeForSDLWindow(SDL_Window *window)
{
SDL_VideoDisplay *pSDLDisplay = SDL_GetDisplayForWindow(window);
if (pSDLDisplay == NULL) {
debug_os2("No display for the window");
return FALSE;
}
return &pSDLDisplay->current_mode;
}
static VOID _mouseCheck(WINDATA *pWinData)
{
SDL_Mouse *pSDLMouse = SDL_GetMouse();
if ((pSDLMouse->relative_mode || (pWinData->window->flags & SDL_WINDOW_MOUSE_GRABBED) != 0) &&
((pWinData->window->flags & SDL_WINDOW_INPUT_FOCUS) != 0)) {
/* We will make a real capture in _wmMouseButton() */
} else {
WinSetCapture(HWND_DESKTOP, NULLHANDLE);
}
}
/* PM window procedure.
* --------------------
*/
static int OS2_ResizeWindowShape(SDL_Window *window);
static VOID _setVisibleRegion(WINDATA *pWinData, BOOL fVisible)
{
SDL_VideoDisplay *pSDLDisplay;
if (! pWinData->pVOData)
return;
pSDLDisplay = (fVisible)? SDL_GetDisplayForWindow(pWinData->window) : NULL;
pWinData->pOutput->SetVisibleRegion(pWinData->pVOData, pWinData->hwnd,
(pSDLDisplay == NULL) ?
NULL : &pSDLDisplay->current_mode,
pWinData->hrgnShape, fVisible);
}
static VOID _wmPaint(WINDATA *pWinData, HWND hwnd)
{
if (pWinData->pVOData == NULL ||
!pWinData->pOutput->Update(pWinData->pVOData, hwnd, NULL, 0)) {
RECTL rectl;
HPS hps;
hps = WinBeginPaint(hwnd, 0, &rectl);
WinFillRect(hps, &rectl, CLR_BLACK);
WinEndPaint(hps);
}
}
static VOID _wmMouseMove(WINDATA *pWinData, SHORT lX, SHORT lY)
{
SDL_Mouse *pSDLMouse = SDL_GetMouse();
POINTL pointl;
BOOL fWinActive = (pWinData->window->flags & SDL_WINDOW_INPUT_FOCUS) != 0;
if (!pSDLMouse->relative_mode || pSDLMouse->relative_mode_warp) {
if (!pSDLMouse->relative_mode && fWinActive &&
((pWinData->window->flags & SDL_WINDOW_MOUSE_GRABBED) != 0) &&
(WinQueryCapture(HWND_DESKTOP) == pWinData->hwnd)) {
pointl.x = lX;
pointl.y = lY;
if (lX < 0)
lX = 0;
else if (lX >= pWinData->window->w)
lX = pWinData->window->w - 1;
if (lY < 0)
lY = 0;
else if (lY >= pWinData->window->h)
lY = pWinData->window->h - 1;
if (lX != pointl.x || lY != pointl.x) {
pointl.x = lX;
pointl.y = lY;
WinMapWindowPoints(pWinData->hwnd, HWND_DESKTOP, &pointl, 1);
pWinData->lSkipWMMouseMove++;
WinSetPointerPos(HWND_DESKTOP, pointl.x, pointl.y);
}
}
SDL_SendMouseMotion(pWinData->window, 0, 0, lX,
pWinData->window->h - lY - 1);
return;
}
if (fWinActive) {
pointl.x = pWinData->window->w / 2;
pointl.y = pWinData->window->h / 2;
WinMapWindowPoints(pWinData->hwnd, HWND_DESKTOP, &pointl, 1);
SDL_SendMouseMotion(pWinData->window, 0, 1,
lX - pointl.x, pointl.y - lY);
pWinData->lSkipWMMouseMove++;
WinSetPointerPos(HWND_DESKTOP, pointl.x, pointl.y);
}
}
static VOID _wmMouseButton(WINDATA *pWinData, ULONG ulButton, BOOL fDown)
{
static ULONG aBtnGROP2SDL[3] = { SDL_BUTTON_LEFT, SDL_BUTTON_RIGHT,
SDL_BUTTON_MIDDLE };
SDL_Mouse *pSDLMouse = SDL_GetMouse();
if ((pSDLMouse->relative_mode || ((pWinData->window->flags & SDL_WINDOW_MOUSE_GRABBED) != 0)) &&
((pWinData->window->flags & SDL_WINDOW_INPUT_FOCUS) != 0) &&
(WinQueryCapture(HWND_DESKTOP) != pWinData->hwnd)) {
/* Mouse should be captured. */
if (pSDLMouse->relative_mode && !pSDLMouse->relative_mode_warp) {
POINTL pointl;
pointl.x = pWinData->window->w / 2;
pointl.y = pWinData->window->h / 2;
WinMapWindowPoints(pWinData->hwnd, HWND_DESKTOP, &pointl, 1);
pWinData->lSkipWMMouseMove++;
WinSetPointerPos(HWND_DESKTOP, pointl.x, pointl.y);
}
WinSetCapture(HWND_DESKTOP, pWinData->hwnd);
}
SDL_SendMouseButton(pWinData->window, 0,
(fDown)? SDL_PRESSED : SDL_RELEASED,
aBtnGROP2SDL[ulButton]);
}
static VOID _wmChar(WINDATA *pWinData, MPARAM mp1, MPARAM mp2)
{
ULONG ulFlags = SHORT1FROMMP(mp1); /* WM_CHAR flags */
ULONG ulVirtualKey = SHORT2FROMMP(mp2); /* Virtual key code VK_* */
ULONG ulCharCode = SHORT1FROMMP(mp2); /* Character code */
ULONG ulScanCode = CHAR4FROMMP(mp1); /* Scan code */
if (((ulFlags & (KC_VIRTUALKEY | KC_KEYUP | KC_ALT)) == (KC_VIRTUALKEY | KC_ALT)) &&
(ulVirtualKey == VK_F4)) {
SDL_SendWindowEvent(pWinData->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
}
if ((ulFlags & KC_SCANCODE) != 0) {
SDL_SendKeyboardKey(((ulFlags & KC_KEYUP) == 0)? SDL_PRESSED : SDL_RELEASED, aSDLScancode[ulScanCode]);
}
if ((ulFlags & KC_CHAR) != 0) {
CHAR acUTF8[4];
LONG lRC = StrUTF8(1, acUTF8, sizeof(acUTF8), (PSZ)&ulCharCode, 1);
SDL_SendKeyboardText((lRC > 0)? acUTF8 : (PSZ)&ulCharCode);
}
}
static VOID _wmMove(WINDATA *pWinData)
{
SDL_DisplayMode *pSDLDisplayMode = _getDisplayModeForSDLWindow(pWinData->window);
POINTL pointl = { 0 };
RECTL rectl;
WinQueryWindowRect(pWinData->hwnd, &rectl);
WinMapWindowPoints(pWinData->hwnd, HWND_DESKTOP, (PPOINTL)&rectl, 2);
WinMapWindowPoints(pWinData->hwnd, HWND_DESKTOP, &pointl, 1);
SDL_SendWindowEvent(pWinData->window, SDL_WINDOWEVENT_MOVED, rectl.xLeft,
pSDLDisplayMode->h - rectl.yTop);
}
static MRESULT _wmDragOver(WINDATA *pWinData, PDRAGINFO pDragInfo)
{
ULONG ulIdx;
PDRAGITEM pDragItem;
USHORT usDrag = DOR_NEVERDROP;
USHORT usDragOp = DO_UNKNOWN;
if (!DrgAccessDraginfo(pDragInfo))
return MRFROM2SHORT(DOR_NEVERDROP, DO_UNKNOWN);
for (ulIdx = 0; ulIdx < pDragInfo->cditem; ulIdx++) {
pDragItem = DrgQueryDragitemPtr(pDragInfo, ulIdx);
/* We accept WPS files only. */
if (!DrgVerifyRMF(pDragItem, "DRM_OS2FILE", NULL)) {
usDrag = DOR_NEVERDROP;
usDragOp = DO_UNKNOWN;
break;
}
if (pDragInfo->usOperation == DO_DEFAULT &&
(pDragItem->fsSupportedOps & DO_COPYABLE) != 0) {
usDrag = DOR_DROP;
usDragOp = DO_COPY;
} else
if (pDragInfo->usOperation == DO_LINK &&
(pDragItem->fsSupportedOps & DO_LINKABLE) != 0) {
usDrag = DOR_DROP;
usDragOp = DO_LINK;
} else {
usDrag = DOR_NODROPOP;
usDragOp = DO_UNKNOWN;
break;
}
}
/* Update window (The DIVE surface spoiled while dragging) */
WinInvalidateRect(pWinData->hwnd, NULL, FALSE);
WinUpdateWindow(pWinData->hwnd);
DrgFreeDraginfo(pDragInfo);
return MPFROM2SHORT(usDrag, usDragOp);
}
static MRESULT _wmDrop(WINDATA *pWinData, PDRAGINFO pDragInfo)
{
ULONG ulIdx;
PDRAGITEM pDragItem;
CHAR acFName[_MAX_PATH];
PCHAR pcFName;
if (!DrgAccessDraginfo(pDragInfo))
return MRFROM2SHORT(DOR_NEVERDROP, 0);
for (ulIdx = 0; ulIdx < pDragInfo->cditem; ulIdx++) {
pDragItem = DrgQueryDragitemPtr(pDragInfo, ulIdx);
if (DrgVerifyRMF(pDragItem, "DRM_OS2FILE", NULL) &&
pDragItem->hstrContainerName != NULLHANDLE &&
pDragItem->hstrSourceName != NULLHANDLE) {
/* Get file name from the item. */
DrgQueryStrName(pDragItem->hstrContainerName, sizeof(acFName), acFName);
pcFName = strchr(acFName, '\0');
DrgQueryStrName(pDragItem->hstrSourceName,
sizeof(acFName) - (pcFName - acFName), pcFName);
/* Send to SDL full file name converted to UTF-8. */
pcFName = OS2_SysToUTF8(acFName);
SDL_SendDropFile(pWinData->window, pcFName);
SDL_free(pcFName);
/* Notify a source that a drag operation is complete. */
if (pDragItem->hwndItem)
DrgSendTransferMsg(pDragItem->hwndItem, DM_ENDCONVERSATION,
(MPARAM)pDragItem->ulItemID,
(MPARAM)DMFL_TARGETSUCCESSFUL);
}
}
DrgDeleteDraginfoStrHandles(pDragInfo);
DrgFreeDraginfo(pDragInfo);
SDL_SendDropComplete(pWinData->window);
return (MRESULT)FALSE;
}
MRESULT EXPENTRY wndFrameProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
HWND hwndClient = WinQueryWindow(hwnd, QW_BOTTOM);
WINDATA * pWinData = (WINDATA *)WinQueryWindowULong(hwndClient, 0);
if (pWinData == NULL)
return WinDefWindowProc(hwnd, msg, mp1, mp2);
/* Send a SDL_SYSWMEVENT if the application wants them */
if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
SDL_SysWMmsg wmmsg;
SDL_VERSION(&wmmsg.version);
wmmsg.subsystem = SDL_SYSWM_OS2;
wmmsg.msg.os2.fFrame = TRUE;
wmmsg.msg.os2.hwnd = hwnd;
wmmsg.msg.os2.msg = msg;
wmmsg.msg.os2.mp1 = mp1;
wmmsg.msg.os2.mp2 = mp2;
SDL_SendSysWMEvent(&wmmsg);
}
switch (msg) {
case WM_MINMAXFRAME:
if ((((PSWP)mp1)->fl & SWP_RESTORE) != 0) {
pWinData->lSkipWMMove += 2;
SDL_SendWindowEvent(pWinData->window, SDL_WINDOWEVENT_RESTORED, 0, 0);
}
if ((((PSWP)mp1)->fl & SWP_MINIMIZE) != 0) {
pWinData->lSkipWMSize++;
pWinData->lSkipWMMove += 2;
SDL_SendWindowEvent(pWinData->window, SDL_WINDOWEVENT_MINIMIZED, 0, 0);
}
if ((((PSWP)mp1)->fl & SWP_MAXIMIZE) != 0) {
SDL_SendWindowEvent(pWinData->window, SDL_WINDOWEVENT_MAXIMIZED, 0, 0);
}
break;
case WM_ADJUSTFRAMEPOS:
if (pWinData->lSkipWMAdjustFramePos > 0) {
pWinData->lSkipWMAdjustFramePos++;
break;
}
if ((pWinData->window->flags & SDL_WINDOW_FULLSCREEN) != 0 &&
(((PSWP)mp1)->fl & SWP_RESTORE) != 0) {
/* Keep fullscreen window size on restore. */
RECTL rectl;
rectl.xLeft = 0;
rectl.yBottom = 0;
rectl.xRight = WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN);
rectl.yTop = WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);
WinCalcFrameRect(hwnd, &rectl, FALSE);
((PSWP)mp1)->x = rectl.xLeft;
((PSWP)mp1)->y = rectl.yBottom;
((PSWP)mp1)->cx = rectl.xRight - rectl.xLeft;
((PSWP)mp1)->cy = rectl.yTop - rectl.yBottom;
}
if ((((PSWP)mp1)->fl & (SWP_SIZE | SWP_MINIMIZE)) == SWP_SIZE) {
if ((pWinData->window->flags & SDL_WINDOW_FULLSCREEN) != 0) {
/* SDL_WINDOW_FULLSCREEN_DESKTOP have flag SDL_WINDOW_FULLSCREEN... */
if (SDL_IsShapedWindow(pWinData->window))
OS2_ResizeWindowShape(pWinData->window);
break;
}
if ((SDL_GetWindowFlags(pWinData->window) & SDL_WINDOW_RESIZABLE) != 0) {
RECTL rectl;
int iMinW, iMinH, iMaxW, iMaxH;
int iWinW, iWinH;
rectl.xLeft = 0;
rectl.yBottom = 0;
SDL_GetWindowSize(pWinData->window,
(int *)&rectl.xRight, (int *)&rectl.yTop);
iWinW = rectl.xRight;
iWinH = rectl.yTop;
SDL_GetWindowMinimumSize(pWinData->window, &iMinW, &iMinH);
SDL_GetWindowMaximumSize(pWinData->window, &iMaxW, &iMaxH);
if (iWinW < iMinW)
rectl.xRight = iMinW;
else if (iMaxW != 0 && iWinW > iMaxW)
rectl.xRight = iMaxW;
if (iWinH < iMinH)
rectl.yTop = iMinW;
else if (iMaxH != 0 && iWinH > iMaxH)
rectl.yTop = iMaxH;
if (rectl.xRight == iWinW && rectl.yTop == iWinH) {
if (SDL_IsShapedWindow(pWinData->window))
OS2_ResizeWindowShape(pWinData->window);
break;
}
WinCalcFrameRect(hwnd, &rectl, FALSE);
((PSWP)mp1)->cx = rectl.xRight - rectl.xLeft;
((PSWP)mp1)->cy = rectl.yTop - rectl.yBottom;
}
}
break;
}
return pWinData->fnWndFrameProc(hwnd, msg, mp1, mp2);
}
MRESULT EXPENTRY wndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
WINDATA *pWinData = (WINDATA *)WinQueryWindowULong(hwnd, 0);
if (pWinData == NULL)
return WinDefWindowProc(hwnd, msg, mp1, mp2);
/* Send a SDL_SYSWMEVENT if the application wants them */
if (SDL_GetEventState(SDL_SYSWMEVENT) == SDL_ENABLE) {
SDL_SysWMmsg wmmsg;
SDL_VERSION(&wmmsg.version);
wmmsg.subsystem = SDL_SYSWM_OS2;
wmmsg.msg.os2.fFrame = FALSE;
wmmsg.msg.os2.hwnd = hwnd;
wmmsg.msg.os2.msg = msg;
wmmsg.msg.os2.mp1 = mp1;
wmmsg.msg.os2.mp2 = mp2;
SDL_SendSysWMEvent(&wmmsg);
}
switch (msg) {
case WM_CLOSE:
case WM_QUIT:
SDL_SendWindowEvent(pWinData->window, SDL_WINDOWEVENT_CLOSE, 0, 0);
if (pWinData->fnUserWndProc == NULL)
return (MRESULT)FALSE;
break;
case WM_PAINT:
_wmPaint(pWinData, hwnd);
break;
case WM_SHOW:
SDL_SendWindowEvent(pWinData->window, (SHORT1FROMMP(mp1) == 0)?
SDL_WINDOWEVENT_HIDDEN :
SDL_WINDOWEVENT_SHOWN ,
0, 0);
break;
case WM_UPDATEFRAME:
/* Return TRUE - no further action for the frame control window procedure */
return (MRESULT)TRUE;
case WM_ACTIVATE:
if ((BOOL)mp1) {
POINTL pointl;
if (SDL_GetKeyboardFocus() != pWinData->window)
SDL_SetKeyboardFocus(pWinData->window);
WinQueryPointerPos(HWND_DESKTOP, &pointl);
WinMapWindowPoints(HWND_DESKTOP, pWinData->hwnd, &pointl, 1);
SDL_SendMouseMotion(pWinData->window, 0, 0,
pointl.x, pWinData->window->h - pointl.y - 1);
} else {
if (SDL_GetKeyboardFocus() == pWinData->window)
SDL_SetKeyboardFocus(NULL);
WinSetCapture(HWND_DESKTOP, NULLHANDLE);
}
break;
case WM_MOUSEMOVE:
WinSetPointer(HWND_DESKTOP, hptrCursor);
if (pWinData->lSkipWMMouseMove > 0)
pWinData->lSkipWMMouseMove--;
else {
_wmMouseMove(pWinData, SHORT1FROMMP(mp1), SHORT2FROMMP(mp1));
}
return (MRESULT)FALSE;
case WM_BUTTON1DOWN:
case WM_BUTTON1DBLCLK:
_wmMouseButton(pWinData, 0, TRUE);
break;
case WM_BUTTON1UP:
_wmMouseButton(pWinData, 0, FALSE);
break;
case WM_BUTTON2DOWN:
case WM_BUTTON2DBLCLK:
_wmMouseButton(pWinData, 1, TRUE);
break;
case WM_BUTTON2UP:
_wmMouseButton(pWinData, 1, FALSE);
break;
case WM_BUTTON3DOWN:
case WM_BUTTON3DBLCLK:
_wmMouseButton(pWinData, 2, TRUE);
break;
case WM_BUTTON3UP:
_wmMouseButton(pWinData, 2, FALSE);
break;
case WM_TRANSLATEACCEL:
/* ALT and acceleration keys not allowed (must be processed in WM_CHAR) */
if (mp1 == NULL || ((PQMSG)mp1)->msg != WM_CHAR)
break;
return (MRESULT)FALSE;
case WM_CHAR:
_wmChar(pWinData, mp1, mp2);
break;
case WM_SIZE:
if (pWinData->lSkipWMSize > 0)
pWinData->lSkipWMSize--;
else {
if ((pWinData->window->flags & SDL_WINDOW_FULLSCREEN) == 0) {
SDL_SendWindowEvent(pWinData->window, SDL_WINDOWEVENT_RESIZED,
SHORT1FROMMP(mp2), SHORT2FROMMP(mp2));
} else {
pWinData->lSkipWMVRNEnabled++;
}
}
break;
case WM_MOVE:
if (pWinData->lSkipWMMove > 0)
pWinData->lSkipWMMove--;
else if ((pWinData->window->flags & SDL_WINDOW_FULLSCREEN) == 0) {
_wmMove(pWinData);
}
break;
case WM_VRNENABLED:
if (pWinData->lSkipWMVRNEnabled > 0)
pWinData->lSkipWMVRNEnabled--;
else {
_setVisibleRegion(pWinData, TRUE);
}
return (MRESULT)TRUE;
case WM_VRNDISABLED:
_setVisibleRegion(pWinData, FALSE);
return (MRESULT)TRUE;
case DM_DRAGOVER:
return _wmDragOver(pWinData, (PDRAGINFO)PVOIDFROMMP(mp1));
case DM_DROP:
return _wmDrop(pWinData, (PDRAGINFO)PVOIDFROMMP(mp1));
}
return (pWinData->fnUserWndProc != NULL)?
pWinData->fnUserWndProc(hwnd, msg, mp1, mp2) :
WinDefWindowProc(hwnd, msg, mp1, mp2);
}
/* SDL routnes.
* ------------
*/
static void OS2_PumpEvents(_THIS)
{
SDL_VideoData *pVData = (SDL_VideoData *)_this->driverdata;
QMSG qmsg;
if (WinPeekMsg(pVData->hab, &qmsg, NULLHANDLE, 0, 0, PM_REMOVE))
WinDispatchMsg(pVData->hab, &qmsg);
}
static WINDATA *_setupWindow(_THIS, SDL_Window *window, HWND hwndFrame,
HWND hwnd)
{
SDL_VideoData *pVData = (SDL_VideoData *)_this->driverdata;
WINDATA *pWinData = SDL_calloc(1, sizeof(WINDATA));
if (pWinData == NULL) {
SDL_OutOfMemory();
return NULL;
}
pWinData->hwnd = hwnd;
pWinData->hwndFrame = hwndFrame;
pWinData->window = window;
window->driverdata = pWinData;
WinSetWindowULong(hwnd, 0, (ULONG)pWinData);
pWinData->fnWndFrameProc = WinSubclassWindow(hwndFrame, wndFrameProc);
pWinData->pOutput = pVData->pOutput;
pWinData->pVOData = pVData->pOutput->Open();
WinSetVisibleRegionNotify(hwnd, TRUE);
return pWinData;
}
static int OS2_CreateWindow(_THIS, SDL_Window *window)
{
RECTL rectl;
HWND hwndFrame, hwnd;
SDL_DisplayMode *pSDLDisplayMode = _getDisplayModeForSDLWindow(window);
ULONG ulFrameFlags = FCF_TASKLIST | FCF_TITLEBAR | FCF_SYSMENU |
FCF_MINBUTTON | FCF_SHELLPOSITION;
ULONG ulSWPFlags = SWP_SIZE | SWP_SHOW | SWP_ZORDER | SWP_ACTIVATE;
WINDATA *pWinData;
if (pSDLDisplayMode == NULL)
return -1;
/* Create a PM window */
if ((window->flags & SDL_WINDOW_RESIZABLE) != 0)
ulFrameFlags |= FCF_SIZEBORDER | FCF_DLGBORDER | FCF_MAXBUTTON;
else if ((window->flags & SDL_WINDOW_BORDERLESS) == 0)
ulFrameFlags |= FCF_DLGBORDER;
if ((window->flags & SDL_WINDOW_MAXIMIZED) != 0)
ulSWPFlags |= SWP_MAXIMIZE;
else if ((window->flags & SDL_WINDOW_MINIMIZED) != 0)
ulSWPFlags |= SWP_MINIMIZE;
hwndFrame = WinCreateStdWindow(HWND_DESKTOP, 0, &ulFrameFlags,
WIN_CLIENT_CLASS, "SDL2", 0, 0, 0, &hwnd);
if (hwndFrame == NULLHANDLE)
return SDL_SetError("Couldn't create window");
/* Setup window data and frame window procedure */
pWinData = _setupWindow(_this, window, hwndFrame, hwnd);
if (pWinData == NULL) {
WinDestroyWindow(hwndFrame);
return -1;
}
/* Show window */
rectl.xLeft = 0;
rectl.yBottom = 0;
rectl.xRight = window->w;
rectl.yTop = window->h;
WinCalcFrameRect(hwndFrame, &rectl, FALSE);
pWinData->lSkipWMSize++;
pWinData->lSkipWMMove++;
WinSetWindowPos(hwndFrame, HWND_TOP, rectl.xLeft, rectl.yBottom,
rectl.xRight - rectl.xLeft, rectl.yTop - rectl.yBottom,
ulSWPFlags);
rectl.xLeft = 0;
rectl.yBottom = 0;
WinMapWindowPoints(hwnd, HWND_DESKTOP, (PPOINTL)&rectl, 1);
window->x = rectl.xLeft;
window->y = pSDLDisplayMode->h - (rectl.yBottom + window->h);
window->flags |= SDL_WINDOW_SHOWN;
return 0;
}
static int OS2_CreateWindowFrom(_THIS, SDL_Window *window, const void *data)
{
SDL_VideoData *pVData = (SDL_VideoData *)_this->driverdata;
CHAR acBuf[256];
CLASSINFO stCI;
HWND hwndUser = (HWND)data;
HWND hwndFrame, hwnd;
ULONG cbText;
PSZ pszText;
WINDATA *pWinData;
SDL_DisplayMode *pSDLDisplayMode = _getDisplayModeForSDLWindow(window);
SWP swp;
POINTL pointl;
debug_os2("Enter");
if (pSDLDisplayMode == NULL)
return -1;
/* User can accept client OR frame window handle.
* Get client and frame window handles. */
WinQueryClassName(hwndUser, sizeof(acBuf), acBuf);
if (!WinQueryClassInfo(pVData->hab, acBuf, &stCI))
return SDL_SetError("Cannot get user window class information");
if ((stCI.flClassStyle & CS_FRAME) == 0) {
/* Client window handle is specified */
hwndFrame = WinQueryWindow(hwndUser, QW_PARENT);
if (hwndFrame == NULLHANDLE)
return SDL_SetError("Cannot get parent window handle");
if ((ULONG)WinSendMsg(hwndFrame, WM_QUERYFRAMEINFO, 0, 0) == 0)
return SDL_SetError("Parent window is not a frame window");
hwnd = hwndUser;
} else {
/* Frame window handle is specified */
hwnd = WinWindowFromID(hwndUser, FID_CLIENT);
if (hwnd == NULLHANDLE)
return SDL_SetError("Cannot get client window handle");
hwndFrame = hwndUser;
WinQueryClassName(hwnd, sizeof(acBuf), acBuf);
if (!WinQueryClassInfo(pVData->hab, acBuf, &stCI))
return SDL_SetError("Cannot get client window class information");
}
/* Check window's reserved storage */
if (stCI.cbWindowData < sizeof(ULONG))
return SDL_SetError("Reserved storage of window must be at least %u bytes", sizeof(ULONG));
/* Set SDL-window title */
cbText = WinQueryWindowTextLength(hwndFrame);
pszText = SDL_stack_alloc(CHAR, cbText + 1);
if (pszText != NULL)
cbText = (pszText != NULL)? WinQueryWindowText(hwndFrame, cbText, pszText) : 0;
if (cbText != 0)
window->title = OS2_SysToUTF8(pszText);
if (pszText != NULL)
SDL_stack_free(pszText);
/* Set SDL-window flags */
window->flags &= ~(SDL_WINDOW_SHOWN | SDL_WINDOW_BORDERLESS |
SDL_WINDOW_RESIZABLE | SDL_WINDOW_MAXIMIZED |
SDL_WINDOW_MINIMIZED | SDL_WINDOW_INPUT_FOCUS);
if (WinIsWindowVisible(hwnd))
window->flags |= SDL_WINDOW_SHOWN;
WinSendMsg(hwndFrame, WM_QUERYBORDERSIZE, MPFROMP(&pointl), 0);
if (pointl.y == WinQuerySysValue(HWND_DESKTOP, SV_CYSIZEBORDER))
window->flags |= SDL_WINDOW_RESIZABLE;
else if (pointl.y <= WinQuerySysValue(HWND_DESKTOP, SV_CYBORDER))
window->flags |= SDL_WINDOW_BORDERLESS;
WinQueryWindowPos(hwndFrame, &swp);
if ((swp.fl & SWP_MAXIMIZE) != 0)
window->flags |= SDL_WINDOW_MAXIMIZED;
if ((swp.fl & SWP_MINIMIZE) != 0)
window->flags |= SDL_WINDOW_MINIMIZED;
pointl.x = 0;
pointl.y = 0;
WinMapWindowPoints(hwnd, HWND_DESKTOP, &pointl, 1);
window->x = pointl.x;
window->y = pSDLDisplayMode->h - (pointl.y + swp.cy);
WinQueryWindowPos(hwnd, &swp);
window->w = swp.cx;
window->h = swp.cy;
/* Setup window data and frame window procedure */
pWinData = _setupWindow(_this, window, hwndFrame, hwnd);
if (pWinData == NULL) {
SDL_free(window->title);
window->title = NULL;
return -1;
}
pWinData->fnUserWndProc = WinSubclassWindow(hwnd, wndProc);
if (WinQueryActiveWindow(HWND_DESKTOP) == hwndFrame)
SDL_SetKeyboardFocus(window);
return 0;
}
static void OS2_DestroyWindow(_THIS, SDL_Window * window)
{
SDL_VideoData *pVData = (SDL_VideoData *)_this->driverdata;
WINDATA *pWinData = (WINDATA *)window->driverdata;
debug_os2("Enter");
if (pWinData == NULL)
return;
if (pWinData->fnUserWndProc == NULL) {
/* Window was created by SDL (OS2_CreateWindow()),
* not by user (OS2_CreateWindowFrom()) */
WinDestroyWindow(pWinData->hwndFrame);
} else {
WinSetWindowULong(pWinData->hwnd, 0, 0);
}
if ((pVData != NULL) && (pWinData->pVOData != NULL)) {
pVData->pOutput->Close(pWinData->pVOData);
pWinData->pVOData = NULL;
}
if (pWinData->hptrIcon != NULLHANDLE) {
WinDestroyPointer(pWinData->hptrIcon);
pWinData->hptrIcon = NULLHANDLE;
}
SDL_free(pWinData);
window->driverdata = NULL;
}
static void OS2_SetWindowTitle(_THIS, SDL_Window *window)
{
PSZ pszTitle = (window->title == NULL)? NULL : OS2_UTF8ToSys(window->title);
WinSetWindowText(((WINDATA *)window->driverdata)->hwndFrame, pszTitle);
SDL_free(pszTitle);
}
static void OS2_SetWindowIcon(_THIS, SDL_Window *window, SDL_Surface *icon)
{
WINDATA *pWinData = (WINDATA *)window->driverdata;
HPOINTER hptr = utilCreatePointer(icon, 0, 0);
if (hptr == NULLHANDLE)
return;
/* Destroy old icon */
if (pWinData->hptrIcon != NULLHANDLE)
WinDestroyPointer(pWinData->hptrIcon);
/* Set new window icon */
pWinData->hptrIcon = hptr;
if (!WinSendMsg(pWinData->hwndFrame, WM_SETICON, MPFROMLONG(hptr), 0)) {
debug_os2("Cannot set icon for the window");
}
}
static void OS2_SetWindowPosition(_THIS, SDL_Window *window)
{
WINDATA *pWinData = (WINDATA *)window->driverdata;
RECTL rectl;
ULONG ulFlags;
SDL_DisplayMode *pSDLDisplayMode = _getDisplayModeForSDLWindow(window);
debug_os2("Enter");
if (pSDLDisplayMode == NULL)
return;
rectl.xLeft = 0;
rectl.yBottom = 0;
rectl.xRight = window->w;
rectl.yTop = window->h;
WinCalcFrameRect(pWinData->hwndFrame, &rectl, FALSE);
if (SDL_ShouldAllowTopmost() &&
(window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) ==
(SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS) )
ulFlags = SWP_ZORDER | SWP_MOVE | SWP_SIZE;
else
ulFlags = SWP_MOVE | SWP_SIZE;
pWinData->lSkipWMSize++;
pWinData->lSkipWMMove++;
WinSetWindowPos(pWinData->hwndFrame, HWND_TOP,
window->x + rectl.xLeft,
(pSDLDisplayMode->h - window->y) - window->h + rectl.yBottom,
rectl.xRight - rectl.xLeft, rectl.yTop - rectl.yBottom,
ulFlags);
}
static void OS2_SetWindowSize(_THIS, SDL_Window *window)
{
debug_os2("Enter");
OS2_SetWindowPosition(_this, window);
}
static void OS2_ShowWindow(_THIS, SDL_Window *window)
{
WINDATA *pWinData = (WINDATA *)window->driverdata;
debug_os2("Enter");
WinShowWindow(pWinData->hwndFrame, TRUE);
}
static void OS2_HideWindow(_THIS, SDL_Window *window)
{
WINDATA *pWinData = (WINDATA *)window->driverdata;
debug_os2("Enter");
WinShowWindow(pWinData->hwndFrame, FALSE);
}
static void OS2_RaiseWindow(_THIS, SDL_Window *window)
{
debug_os2("Enter");
OS2_SetWindowPosition(_this, window);
}
static void OS2_MaximizeWindow(_THIS, SDL_Window *window)
{
WINDATA *pWinData = (WINDATA *)window->driverdata;
debug_os2("Enter");
WinSetWindowPos(pWinData->hwndFrame, HWND_TOP, 0, 0, 0, 0, SWP_MAXIMIZE);
}
static void OS2_MinimizeWindow(_THIS, SDL_Window *window)
{
WINDATA *pWinData = (WINDATA *)window->driverdata;
debug_os2("Enter");
WinSetWindowPos(pWinData->hwndFrame, HWND_TOP, 0, 0, 0, 0, SWP_MINIMIZE | SWP_DEACTIVATE);
}
static void OS2_RestoreWindow(_THIS, SDL_Window *window)
{
WINDATA *pWinData = (WINDATA *)window->driverdata;
debug_os2("Enter");
WinSetWindowPos(pWinData->hwndFrame, HWND_TOP, 0, 0, 0, 0, SWP_RESTORE);
}
static void OS2_SetWindowBordered(_THIS, SDL_Window * window,
SDL_bool bordered)
{
WINDATA *pWinData = (WINDATA *)window->driverdata;
ULONG ulStyle = WinQueryWindowULong(pWinData->hwndFrame, QWL_STYLE);
RECTL rectl;
debug_os2("Enter");
/* New frame sytle */
if (bordered)
ulStyle |= ((window->flags & SDL_WINDOW_RESIZABLE) != 0) ? FS_SIZEBORDER : FS_DLGBORDER;
else
ulStyle &= ~(FS_SIZEBORDER | FS_BORDER | FS_DLGBORDER);
/* Save client window position */
WinQueryWindowRect(pWinData->hwnd, &rectl);
WinMapWindowPoints(pWinData->hwnd, HWND_DESKTOP, (PPOINTL)&rectl, 2);
/* Change the frame */
WinSetWindowULong(pWinData->hwndFrame, QWL_STYLE, ulStyle);
WinSendMsg(pWinData->hwndFrame, WM_UPDATEFRAME, MPFROMLONG(FCF_BORDER), 0);
/* Restore client window position */
WinCalcFrameRect(pWinData->hwndFrame, &rectl, FALSE);
pWinData->lSkipWMMove++;
WinSetWindowPos(pWinData->hwndFrame, HWND_TOP, rectl.xLeft, rectl.yBottom,
rectl.xRight - rectl.xLeft,
rectl.yTop - rectl.yBottom,
SWP_SIZE | SWP_MOVE | SWP_NOADJUST);
}
static void OS2_SetWindowFullscreen(_THIS, SDL_Window *window,
SDL_VideoDisplay *display,
SDL_bool fullscreen)
{
RECTL rectl;
ULONG ulFlags;
WINDATA *pWinData = (WINDATA *)window->driverdata;
SDL_DisplayMode *pSDLDisplayMode = &display->current_mode;
debug_os2("Enter, fullscreen: %u", fullscreen);
if (pSDLDisplayMode == NULL)
return;
if (SDL_ShouldAllowTopmost() &&
(window->flags & (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS)) == (SDL_WINDOW_FULLSCREEN|SDL_WINDOW_INPUT_FOCUS))
ulFlags = SWP_SIZE | SWP_MOVE | SWP_ZORDER | SWP_NOADJUST;
else
ulFlags = SWP_SIZE | SWP_MOVE | SWP_NOADJUST;
if (fullscreen) {
rectl.xLeft = 0;
rectl.yBottom = 0;
rectl.xRight = pSDLDisplayMode->w;
rectl.yTop = pSDLDisplayMode->h;
/* We need send the restore command now to allow WinCalcFrameRect() */
WinSetWindowPos(pWinData->hwndFrame, HWND_TOP, 0, 0, 0, 0, SWP_RESTORE);
} else {
pWinData->lSkipWMMove++;
rectl.xLeft = window->windowed.x;
rectl.yTop = pSDLDisplayMode->h - window->windowed.y;
rectl.xRight = rectl.xLeft + window->windowed.w;
rectl.yBottom = rectl.yTop - window->windowed.h;
}
if (!WinCalcFrameRect(pWinData->hwndFrame, &rectl, FALSE)) {
debug_os2("WinCalcFrameRect() failed");
}
else if (!WinSetWindowPos(pWinData->hwndFrame, HWND_TOP,
rectl.xLeft, rectl.yBottom,
rectl.xRight - rectl.xLeft, rectl.yTop - rectl.yBottom,
ulFlags)) {
debug_os2("WinSetWindowPos() failed");
}
}
static SDL_bool OS2_GetWindowWMInfo(_THIS, SDL_Window * window,
struct SDL_SysWMinfo *info)
{
WINDATA *pWinData = (WINDATA *)window->driverdata;
if (info->version.major <= SDL_MAJOR_VERSION) {
info->subsystem = SDL_SYSWM_OS2;
info->info.os2.hwnd = pWinData->hwnd;
info->info.os2.hwndFrame = pWinData->hwndFrame;
return SDL_TRUE;
}
SDL_SetError("Application not compiled with SDL %u.%u",
SDL_MAJOR_VERSION, SDL_MINOR_VERSION);
return SDL_FALSE;
}
static void OS2_OnWindowEnter(_THIS, SDL_Window * window)
{
}
static int OS2_SetWindowHitTest(SDL_Window *window, SDL_bool enabled)
{
debug_os2("Enter");
return 0;
}
static void OS2_SetWindowMouseGrab(_THIS, SDL_Window *window, SDL_bool grabbed)
{
WINDATA *pWinData = (WINDATA *)window->driverdata;
debug_os2("Enter, %u", grabbed);
_mouseCheck(pWinData);
}
/* Shaper
*/
typedef struct _SHAPERECTS {
PRECTL pRects;
ULONG cRects;
ULONG ulWinHeight;
} SHAPERECTS;
static void _combineRectRegions(SDL_ShapeTree *node, void *closure)
{
SHAPERECTS *pShapeRects = (SHAPERECTS *)closure;
PRECTL pRect;
/* Expand rectangles list */
if ((pShapeRects->cRects & 0x0F) == 0) {
pRect = SDL_realloc(pShapeRects->pRects, (pShapeRects->cRects + 0x10) * sizeof(RECTL));
if (pRect == NULL)
return;
pShapeRects->pRects = pRect;
}
/* Add a new rectangle */
pRect = &pShapeRects->pRects[pShapeRects->cRects];
pShapeRects->cRects++;
/* Fill rectangle data */
pRect->xLeft = node->data.shape.x;
pRect->yTop = pShapeRects->ulWinHeight - node->data.shape.y;
pRect->xRight += node->data.shape.w;
pRect->yBottom = pRect->yTop - node->data.shape.h;
}
static SDL_WindowShaper* OS2_CreateShaper(SDL_Window * window)
{
SDL_WindowShaper* pSDLShaper = SDL_malloc(sizeof(SDL_WindowShaper));
debug_os2("Enter");
pSDLShaper->window = window;
pSDLShaper->mode.mode = ShapeModeDefault;
pSDLShaper->mode.parameters.binarizationCutoff = 1;
pSDLShaper->userx = 0;
pSDLShaper->usery = 0;
pSDLShaper->driverdata = (SDL_ShapeTree *)NULL;
window->shaper = pSDLShaper;
if (OS2_ResizeWindowShape(window) != 0) {
window->shaper = NULL;
SDL_free(pSDLShaper);
return NULL;
}
return pSDLShaper;
}
static int OS2_SetWindowShape(SDL_WindowShaper *shaper, SDL_Surface *shape,
SDL_WindowShapeMode *shape_mode)
{
SDL_ShapeTree *pShapeTree;
WINDATA *pWinData;
SHAPERECTS stShapeRects = { 0 };
HPS hps;
debug_os2("Enter");
if (shaper == NULL || shape == NULL ||
(shape->format->Amask == 0 && shape_mode->mode != ShapeModeColorKey) ||
shape->w != shaper->window->w || shape->h != shaper->window->h) {
return SDL_INVALID_SHAPE_ARGUMENT;
}
if (shaper->driverdata != NULL)
SDL_FreeShapeTree((SDL_ShapeTree **)&shaper->driverdata);
pShapeTree = SDL_CalculateShapeTree(*shape_mode, shape);
shaper->driverdata = pShapeTree;
stShapeRects.ulWinHeight = shaper->window->h;
SDL_TraverseShapeTree(pShapeTree, &_combineRectRegions, &stShapeRects);
pWinData = (WINDATA *)shaper->window->driverdata;
hps = WinGetPS(pWinData->hwnd);
if (pWinData->hrgnShape != NULLHANDLE)
GpiDestroyRegion(hps, pWinData->hrgnShape);
pWinData->hrgnShape = (stShapeRects.pRects == NULL) ? NULLHANDLE :
GpiCreateRegion(hps, stShapeRects.cRects, stShapeRects.pRects);
WinReleasePS(hps);
SDL_free(stShapeRects.pRects);
WinSendMsg(pWinData->hwnd, WM_VRNENABLED, 0, 0);
return 0;
}
static int OS2_ResizeWindowShape(SDL_Window *window)
{
debug_os2("Enter");
if (window == NULL)
return -1;
if (window->x != -1000) {
if (window->shaper->driverdata != NULL)
SDL_FreeShapeTree((SDL_ShapeTree **)window->shaper->driverdata);
if (window->shaper->hasshape == SDL_TRUE) {
window->shaper->userx = window->x;
window->shaper->usery = window->y;
SDL_SetWindowPosition(window, -1000, -1000);
}
}
return 0;
}
/* Frame buffer
*/
static void OS2_DestroyWindowFramebuffer(_THIS, SDL_Window *window)
{
WINDATA *pWinData = (WINDATA *)window->driverdata;
debug_os2("Enter");
if (pWinData != NULL && pWinData->pVOData != NULL)
pWinData->pOutput->VideoBufFree(pWinData->pVOData);
}
static int OS2_CreateWindowFramebuffer(_THIS, SDL_Window *window,
Uint32 *format, void **pixels,
int *pitch)
{
WINDATA *pWinData = (WINDATA *)window->driverdata;
SDL_VideoDisplay *pSDLDisplay = SDL_GetDisplayForWindow(window);
SDL_DisplayMode *pSDLDisplayMode;
MODEDATA *pModeData;
ULONG ulWidth, ulHeight;
debug_os2("Enter");
if (pSDLDisplay == NULL) {
debug_os2("No display for the window");
return -1;
}
pSDLDisplayMode = &pSDLDisplay->current_mode;
pModeData = (MODEDATA *)pSDLDisplayMode->driverdata;
if (pModeData == NULL)
return SDL_SetError("No mode data for the display");
SDL_GetWindowSize(window, (int *)&ulWidth, (int *)&ulHeight);
debug_os2("Window size: %u x %u", ulWidth, ulHeight);
*pixels = pWinData->pOutput->VideoBufAlloc(
pWinData->pVOData, ulWidth, ulHeight, pModeData->ulDepth,
pModeData->fccColorEncoding, (PULONG)pitch);
if (*pixels == NULL)
return -1;
*format = pSDLDisplayMode->format;
debug_os2("Pitch: %u, frame buffer: 0x%X.", *pitch, *pixels);
WinSendMsg(pWinData->hwnd, WM_VRNENABLED, 0, 0);
return 0;
}
static int OS2_UpdateWindowFramebuffer(_THIS, SDL_Window * window,
const SDL_Rect *rects, int numrects)
{
WINDATA *pWinData = (WINDATA *)window->driverdata;
return pWinData->pOutput->Update(pWinData->pVOData, pWinData->hwnd,
(SDL_Rect *)rects, (ULONG)numrects)
? 0 : -1;
}
/* Clipboard
*/
static int OS2_SetClipboardText(_THIS, const char *text)
{
SDL_VideoData *pVData = (SDL_VideoData *)_this->driverdata;
PSZ pszClipboard;
PSZ pszText = (text == NULL)? NULL : OS2_UTF8ToSys(text);
ULONG cbText;
ULONG ulRC;
BOOL fSuccess;
debug_os2("Enter");
if (pszText == NULL)
return -1;
cbText = SDL_strlen(pszText);
ulRC = DosAllocSharedMem((PPVOID)&pszClipboard, 0, cbText + 1,
PAG_COMMIT | PAG_READ | PAG_WRITE |
OBJ_GIVEABLE | OBJ_GETTABLE | OBJ_TILE);
if (ulRC != NO_ERROR) {
debug_os2("DosAllocSharedMem() failed, rc = %u", ulRC);
SDL_free(pszText);
return -1;
}
strcpy(pszClipboard, pszText);
SDL_free(pszText);
if (!WinOpenClipbrd(pVData->hab)) {
debug_os2("WinOpenClipbrd() failed");
fSuccess = FALSE;
} else {
WinEmptyClipbrd(pVData->hab);
fSuccess = WinSetClipbrdData(pVData->hab, (ULONG)pszClipboard, CF_TEXT, CFI_POINTER);
if (!fSuccess) {
debug_os2("WinOpenClipbrd() failed");
}
WinCloseClipbrd(pVData->hab);
}
if (!fSuccess) {
DosFreeMem(pszClipboard);
return -1;
}
return 0;
}
static char *OS2_GetClipboardText(_THIS)
{
SDL_VideoData *pVData = (SDL_VideoData *)_this->driverdata;
PSZ pszClipboard = NULL;
if (!WinOpenClipbrd(pVData->hab)) {
debug_os2("WinOpenClipbrd() failed");
} else {
pszClipboard = (PSZ)WinQueryClipbrdData(pVData->hab, CF_TEXT);
if (pszClipboard != NULL)
pszClipboard = OS2_SysToUTF8(pszClipboard);
WinCloseClipbrd(pVData->hab);
}
return (pszClipboard == NULL) ? SDL_strdup("") : pszClipboard;
}
static SDL_bool OS2_HasClipboardText(_THIS)
{
SDL_VideoData *pVData = (SDL_VideoData *)_this->driverdata;
SDL_bool fClipboard;
if (!WinOpenClipbrd(pVData->hab)) {
debug_os2("WinOpenClipbrd() failed");
return SDL_FALSE;
}
fClipboard = ((PSZ)WinQueryClipbrdData(pVData->hab, CF_TEXT) != NULL)?
SDL_TRUE : SDL_FALSE;
WinCloseClipbrd(pVData->hab);
return fClipboard;
}
static int OS2_VideoInit(_THIS)
{
SDL_VideoData *pVData;
PTIB tib;
PPIB pib;
/* Create SDL video driver private data */
pVData = SDL_calloc(1, sizeof(SDL_VideoData));
if (pVData == NULL)
return SDL_OutOfMemory();
/* Change process type code for use Win* API from VIO session */
DosGetInfoBlocks(&tib, &pib);
if (pib->pib_ultype == 2 || pib->pib_ultype == 0) {
/* VIO windowable or fullscreen protect-mode session */
pib->pib_ultype = 3; /* Presentation Manager protect-mode session */
}
/* PM initialization */
pVData->hab = WinInitialize(0);
pVData->hmq = WinCreateMsgQueue(pVData->hab, 0);
if (pVData->hmq == NULLHANDLE) {
SDL_free(pVData);
return SDL_SetError("Message queue cannot be created.");
}
if (!WinRegisterClass(pVData->hab, WIN_CLIENT_CLASS, wndProc,
CS_SIZEREDRAW | CS_MOVENOTIFY | CS_SYNCPAINT,
sizeof(SDL_VideoData*))) {
SDL_free(pVData);
return SDL_SetError("Window class not successfully registered.");
}
if (stricmp(_this->name, OS2DRIVER_NAME_VMAN) == 0)
pVData->pOutput = &voVMan;
else
pVData->pOutput = &voDive;
_this->driverdata = pVData;
/* Add display */
{
SDL_VideoDisplay stSDLDisplay;
SDL_DisplayMode stSDLDisplayMode;
DISPLAYDATA *pDisplayData;
MODEDATA *pModeData;
VIDEOOUTPUTINFO stVOInfo;
if (!pVData->pOutput->QueryInfo(&stVOInfo)) {
SDL_free(pVData);
return SDL_SetError("Video mode query failed.");
}
SDL_zero(stSDLDisplay); SDL_zero(stSDLDisplayMode);
stSDLDisplayMode.format = _getSDLPixelFormat(stVOInfo.ulBPP,
stVOInfo.fccColorEncoding);
stSDLDisplayMode.w = stVOInfo.ulHorizResolution;
stSDLDisplayMode.h = stVOInfo.ulVertResolution;
stSDLDisplayMode.refresh_rate = 0;
stSDLDisplayMode.driverdata = NULL;
pModeData = SDL_malloc(sizeof(MODEDATA));
if (pModeData != NULL) {
pModeData->ulDepth = stVOInfo.ulBPP;
pModeData->fccColorEncoding = stVOInfo.fccColorEncoding;
pModeData->ulScanLineBytes = stVOInfo.ulScanLineSize;
stSDLDisplayMode.driverdata = pModeData;
}
stSDLDisplay.name = "Primary";
stSDLDisplay.desktop_mode = stSDLDisplayMode;
stSDLDisplay.current_mode = stSDLDisplayMode;
stSDLDisplay.driverdata = NULL;
stSDLDisplay.num_display_modes = 0;
pDisplayData = SDL_malloc(sizeof(DISPLAYDATA));
if (pDisplayData != NULL) {
HPS hps = WinGetPS(HWND_DESKTOP);
HDC hdc = GpiQueryDevice(hps);
/* May be we can use CAPS_HORIZONTAL_RESOLUTION and
* CAPS_VERTICAL_RESOLUTION - pels per meter? */
DevQueryCaps(hdc, CAPS_HORIZONTAL_FONT_RES, 1,
(PLONG)&pDisplayData->ulDPIHor);
DevQueryCaps(hdc, CAPS_VERTICAL_FONT_RES, 1,
(PLONG)&pDisplayData->ulDPIVer);
WinReleasePS(hps);
pDisplayData->ulDPIDiag = SDL_ComputeDiagonalDPI(
stVOInfo.ulHorizResolution, stVOInfo.ulVertResolution,
(float)stVOInfo.ulHorizResolution / pDisplayData->ulDPIHor,
(float)stVOInfo.ulVertResolution / pDisplayData->ulDPIVer);
stSDLDisplayMode.driverdata = pDisplayData;
}
SDL_AddVideoDisplay(&stSDLDisplay, SDL_FALSE);
}
OS2_InitMouse(_this, pVData->hab);
return 0;
}
static void OS2_VideoQuit(_THIS)
{
SDL_VideoData *pVData = (SDL_VideoData *)_this->driverdata;
OS2_QuitMouse(_this);
WinDestroyMsgQueue(pVData->hmq);
WinTerminate(pVData->hab);
/* our caller SDL_VideoQuit() already frees display_modes, driverdata, etc. */
}
static int OS2_GetDisplayBounds(_THIS, SDL_VideoDisplay *display,
SDL_Rect *rect)
{
debug_os2("Enter");
rect->x = 0;
rect->y = 0;
rect->w = display->desktop_mode.w;
rect->h = display->desktop_mode.h;
return 0;
}
static int OS2_GetDisplayDPI(_THIS, SDL_VideoDisplay *display, float *ddpi,
float *hdpi, float *vdpi)
{
DISPLAYDATA *pDisplayData = (DISPLAYDATA *)display->driverdata;
debug_os2("Enter");
if (pDisplayData == NULL)
return -1;
if (ddpi != NULL)
*hdpi = pDisplayData->ulDPIDiag;
if (hdpi != NULL)
*hdpi = pDisplayData->ulDPIHor;
if (vdpi != NULL)
*vdpi = pDisplayData->ulDPIVer;
return 0;
}
static void OS2_GetDisplayModes(_THIS, SDL_VideoDisplay *display)
{
debug_os2("Enter");
SDL_AddDisplayMode(display, &display->current_mode);
}
static int OS2_SetDisplayMode(_THIS, SDL_VideoDisplay *display,
SDL_DisplayMode *mode)
{
debug_os2("Enter");
return -1;
}
static void OS2_DeleteDevice(SDL_VideoDevice *device)
{
SDL_free(device);
}
static SDL_VideoDevice *OS2_CreateDevice(int devindex)
{
SDL_VideoDevice *device;
/* Initialize all variables that we clean on shutdown */
device = (SDL_VideoDevice *)SDL_calloc(1, sizeof(SDL_VideoDevice));
if (!device) {
SDL_OutOfMemory();
return NULL;
}
/* Set the function pointers */
device->VideoInit = OS2_VideoInit;
device->VideoQuit = OS2_VideoQuit;
device->GetDisplayBounds = OS2_GetDisplayBounds;
device->GetDisplayDPI = OS2_GetDisplayDPI;
device->GetDisplayModes = OS2_GetDisplayModes;
device->SetDisplayMode = OS2_SetDisplayMode;
device->PumpEvents = OS2_PumpEvents;
device->CreateSDLWindow = OS2_CreateWindow;
device->CreateSDLWindowFrom = OS2_CreateWindowFrom;
device->DestroyWindow = OS2_DestroyWindow;
device->SetWindowTitle = OS2_SetWindowTitle;
device->SetWindowIcon = OS2_SetWindowIcon;
device->SetWindowPosition = OS2_SetWindowPosition;
device->SetWindowSize = OS2_SetWindowSize;
device->ShowWindow = OS2_ShowWindow;
device->HideWindow = OS2_HideWindow;
device->RaiseWindow = OS2_RaiseWindow;
device->MaximizeWindow = OS2_MaximizeWindow;
device->MinimizeWindow = OS2_MinimizeWindow;
device->RestoreWindow = OS2_RestoreWindow;
device->SetWindowBordered = OS2_SetWindowBordered;
device->SetWindowFullscreen = OS2_SetWindowFullscreen;
device->GetWindowWMInfo = OS2_GetWindowWMInfo;
device->OnWindowEnter = OS2_OnWindowEnter;
device->SetWindowHitTest = OS2_SetWindowHitTest;
device->SetWindowMouseGrab = OS2_SetWindowMouseGrab;
device->CreateWindowFramebuffer = OS2_CreateWindowFramebuffer;
device->UpdateWindowFramebuffer = OS2_UpdateWindowFramebuffer;
device->DestroyWindowFramebuffer = OS2_DestroyWindowFramebuffer;
device->SetClipboardText = OS2_SetClipboardText;
device->GetClipboardText = OS2_GetClipboardText;
device->HasClipboardText = OS2_HasClipboardText;
device->shape_driver.CreateShaper = OS2_CreateShaper;
device->shape_driver.SetWindowShape = OS2_SetWindowShape;
device->shape_driver.ResizeWindowShape = OS2_ResizeWindowShape;
device->free = OS2_DeleteDevice;
return device;
}
static SDL_VideoDevice *OS2DIVE_CreateDevice(int devindex)
{
VIDEOOUTPUTINFO stVOInfo;
if (!voDive.QueryInfo(&stVOInfo)) {
return NULL;
}
return OS2_CreateDevice(devindex);
}
static SDL_VideoDevice *OS2VMAN_CreateDevice(int devindex)
{
VIDEOOUTPUTINFO stVOInfo;
if (!voVMan.QueryInfo(&stVOInfo)) {
return NULL;
}
return OS2_CreateDevice(devindex);
}
/* Both bootstraps for DIVE and VMAN are uing same function OS2_CreateDevice().
* Video output system will be selected in OS2_VideoInit() by driver name. */
VideoBootStrap OS2DIVE_bootstrap =
{
OS2DRIVER_NAME_DIVE, "OS/2 video driver",
OS2DIVE_CreateDevice
};
VideoBootStrap OS2VMAN_bootstrap =
{
OS2DRIVER_NAME_VMAN, "OS/2 video driver",
OS2VMAN_CreateDevice
};
#endif /* SDL_VIDEO_DRIVER_OS2 */
/* vi: set ts=4 sw=4 expandtab: */