From 74cfb81dbb5765aab963cce775437b0023daa1ee Mon Sep 17 00:00:00 2001 From: Ozkan Sezer Date: Wed, 14 Oct 2020 23:01:00 +0300 Subject: [PATCH] os2: add port files for SDL2-2.0.4 from Andrey Vasilkin only geniconv/iconv.h (was from LGPL libiconv) is replaced with a generic minimal iconv.h based on public knowledge. --- src/audio/os2/SDL_os2audio.c | 472 +++++++ src/audio/os2/SDL_os2audio.h | 53 + src/core/os2/SDL_os2.c | 36 + src/core/os2/SDL_os2.h | 31 + src/core/os2/geniconv/geniconv.c | 143 ++ src/core/os2/geniconv/geniconv.h | 59 + src/core/os2/geniconv/iconv.h | 21 + src/core/os2/geniconv/makefile | 37 + src/core/os2/geniconv/os2cp.c | 383 +++++ src/core/os2/geniconv/os2cp.h | 9 + src/core/os2/geniconv/os2iconv.c | 264 ++++ src/core/os2/geniconv/sys2utf8.c | 97 ++ src/core/os2/geniconv/test.c | 45 + src/filesystem/os2/SDL_sysfilesystem.c | 122 ++ src/loadso/os2/SDL_sysloadso.c | 79 ++ src/thread/os2/SDL_sysmutex.c | 132 ++ src/thread/os2/SDL_syssem.c | 196 +++ src/thread/os2/SDL_systhread.c | 187 +++ src/thread/os2/SDL_systhread_c.h | 25 + src/thread/os2/SDL_systls.c | 89 ++ src/thread/os2/SDL_systls_c.h | 38 + src/timer/os2/SDL_systimer.c | 189 +++ src/video/os2/SDL_os2dive.c | 348 +++++ src/video/os2/SDL_os2messagebox.c | 593 ++++++++ src/video/os2/SDL_os2messagebox.h | 29 + src/video/os2/SDL_os2mouse.c | 204 +++ src/video/os2/SDL_os2mouse.h | 33 + src/video/os2/SDL_os2output.h | 54 + src/video/os2/SDL_os2util.c | 118 ++ src/video/os2/SDL_os2util.h | 38 + src/video/os2/SDL_os2video.c | 1786 ++++++++++++++++++++++++ src/video/os2/SDL_os2video.h | 83 ++ src/video/os2/SDL_os2vman.c | 512 +++++++ test/testnativeos2.c | 59 + 34 files changed, 6564 insertions(+) create mode 100644 src/audio/os2/SDL_os2audio.c create mode 100644 src/audio/os2/SDL_os2audio.h create mode 100644 src/core/os2/SDL_os2.c create mode 100644 src/core/os2/SDL_os2.h create mode 100644 src/core/os2/geniconv/geniconv.c create mode 100644 src/core/os2/geniconv/geniconv.h create mode 100644 src/core/os2/geniconv/iconv.h create mode 100644 src/core/os2/geniconv/makefile create mode 100644 src/core/os2/geniconv/os2cp.c create mode 100644 src/core/os2/geniconv/os2cp.h create mode 100644 src/core/os2/geniconv/os2iconv.c create mode 100644 src/core/os2/geniconv/sys2utf8.c create mode 100644 src/core/os2/geniconv/test.c create mode 100644 src/filesystem/os2/SDL_sysfilesystem.c create mode 100644 src/loadso/os2/SDL_sysloadso.c create mode 100644 src/thread/os2/SDL_sysmutex.c create mode 100644 src/thread/os2/SDL_syssem.c create mode 100644 src/thread/os2/SDL_systhread.c create mode 100644 src/thread/os2/SDL_systhread_c.h create mode 100644 src/thread/os2/SDL_systls.c create mode 100644 src/thread/os2/SDL_systls_c.h create mode 100644 src/timer/os2/SDL_systimer.c create mode 100644 src/video/os2/SDL_os2dive.c create mode 100644 src/video/os2/SDL_os2messagebox.c create mode 100644 src/video/os2/SDL_os2messagebox.h create mode 100644 src/video/os2/SDL_os2mouse.c create mode 100644 src/video/os2/SDL_os2mouse.h create mode 100644 src/video/os2/SDL_os2output.h create mode 100644 src/video/os2/SDL_os2util.c create mode 100644 src/video/os2/SDL_os2util.h create mode 100644 src/video/os2/SDL_os2video.c create mode 100644 src/video/os2/SDL_os2video.h create mode 100644 src/video/os2/SDL_os2vman.c create mode 100644 test/testnativeos2.c diff --git a/src/audio/os2/SDL_os2audio.c b/src/audio/os2/SDL_os2audio.c new file mode 100644 index 000000000..786deb1d2 --- /dev/null +++ b/src/audio/os2/SDL_os2audio.c @@ -0,0 +1,472 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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_AUDIO_DRIVER_OS2 + +/* Allow access to a raw mixing buffer */ + +#include "../../core/os2/SDL_os2.h" + +#include "SDL_timer.h" +#include "SDL_audio.h" +#include "../SDL_audio_c.h" +#include "SDL_os2audio.h" + +/* +void lockIncr(volatile int *piVal); +#pragma aux lockIncr = \ +" lock add [eax], 1 "\ +parm [eax]; + +void lockDecr(volatile int *piVal); +#pragma aux lockDecr = \ +" lock sub [eax], 1 "\ +parm [eax]; +*/ + + +static ULONG _getEnvULong(PSZ pszName, ULONG ulMax, ULONG ulDefault) +{ + ULONG ulValue; + PCHAR pcEnd; + PSZ pszEnvVal = SDL_getenv( pszName ); + + if ( pszEnvVal == NULL ) + return ulDefault; + + ulValue = SDL_strtoul( (const char *)pszEnvVal, &pcEnd, 10 ); + return ( pcEnd == pszEnvVal ) || ( ulValue > ulMax ) ? ulDefault : ulMax; +} + +static int _MCIError(PSZ pszFunc, ULONG ulResult) +{ + CHAR acBuf[128]; + + mciGetErrorString( ulResult, (PCHAR)&acBuf, sizeof(acBuf) ); + return SDL_SetError( "[%s] %s", pszFunc, &acBuf ); +} + +static void _mixIOError(PSZ pszFunction, ULONG ulRC) +{ + debug( "%s() - failed, rc = 0x%X (%s)", + pszFunction, ulRC, + ulRC == MCIERR_INVALID_MODE ? "Mixer mode does not match request" + : ulRC == MCIERR_INVALID_BUFFER ? "Caller sent an invalid buffer" + : "unknown" ); +} + +LONG APIENTRY cbAudioWriteEvent(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, + ULONG ulFlags) +{ + PSDL_PrivateAudioData pAData = (PSDL_PrivateAudioData)pBuffer->ulUserParm; + ULONG ulRC; + + if ( ulFlags != MIX_WRITE_COMPLETE ) + { + debug( "flags = 0x%X", ulFlags ); + return 0; + } + +// lockDecr( (int *)&pAData->ulQueuedBuf ); + ulRC = DosPostEventSem( pAData->hevBuf ); + if ( ( ulRC != NO_ERROR ) && ( ulRC != ERROR_ALREADY_POSTED ) ) + debug( "DosPostEventSem(), rc = %u", ulRC ); + + return 1; // It seems, return value is not matter. +} + +LONG APIENTRY cbAudioReadEvent(ULONG ulStatus, PMCI_MIX_BUFFER pBuffer, + ULONG ulFlags) +{ + PSDL_PrivateAudioData pAData = (PSDL_PrivateAudioData)pBuffer->ulUserParm; + ULONG ulRC; + + if ( ulFlags != MIX_READ_COMPLETE ) + { + debug( "flags = 0x%X", ulFlags ); + return 0; + } + + pAData->stMCIMixSetup.pmixRead( pAData->stMCIMixSetup.ulMixHandle, pBuffer, + 1 ); + + ulRC = DosPostEventSem( pAData->hevBuf ); + if ( ( ulRC != NO_ERROR ) && ( ulRC != ERROR_ALREADY_POSTED ) ) + debug( "DosPostEventSem(), rc = %u", ulRC ); + + return 1; +} + + +static void OS2_DetectDevices(void) +{ + MCI_SYSINFO_PARMS stMCISysInfo; + CHAR acBuf[256]; + ULONG ulDevicesNum; + MCI_SYSINFO_LOGDEVICE stLogDevice; + MCI_SYSINFO_PARMS stSysInfoParams; + ULONG ulRC; + ULONG ulHandle = 0; + + acBuf[0] = '\0'; + stMCISysInfo.pszReturn = &acBuf; + stMCISysInfo.ulRetSize = sizeof(acBuf); + stMCISysInfo.usDeviceType = MCI_DEVTYPE_AUDIO_AMPMIX; + ulRC = mciSendCommand( 0, MCI_SYSINFO, MCI_WAIT | MCI_SYSINFO_QUANTITY, + &stMCISysInfo, 0 ); + if ( ulRC != NO_ERROR ) + { + debug( "MCI_SYSINFO, MCI_SYSINFO_QUANTITY - failed, rc = 0x%X", ulRC ); + return; + } + + ulDevicesNum = atol( stMCISysInfo.pszReturn ); + + for( stSysInfoParams.ulNumber = 0; stSysInfoParams.ulNumber < ulDevicesNum; + stSysInfoParams.ulNumber++ ) + { + // Get device install name. + stSysInfoParams.pszReturn = &acBuf; + stSysInfoParams.ulRetSize = sizeof( acBuf ); + stSysInfoParams.usDeviceType = MCI_DEVTYPE_AUDIO_AMPMIX; + ulRC = mciSendCommand( 0, MCI_SYSINFO, MCI_WAIT | MCI_SYSINFO_INSTALLNAME, + &stSysInfoParams, 0 ); + if ( ulRC != NO_ERROR ) + { + debug( "MCI_SYSINFO, MCI_SYSINFO_INSTALLNAME - failed, rc = 0x%X", ulRC ); + continue; + } + + // Get textual product description. + stSysInfoParams.ulItem = MCI_SYSINFO_QUERY_DRIVER; + stSysInfoParams.pSysInfoParm = &stLogDevice; + strcpy( &stLogDevice.szInstallName, stSysInfoParams.pszReturn ); + ulRC = mciSendCommand( 0, MCI_SYSINFO, MCI_WAIT | MCI_SYSINFO_ITEM, + &stSysInfoParams, 0 ); + if ( ulRC != NO_ERROR ) + { + debug( "MCI_SYSINFO, MCI_SYSINFO_ITEM - failed, rc = 0x%X", ulRC ); + continue; + } + + ulHandle++; + SDL_AddAudioDevice( 0, &stLogDevice.szProductInfo, (void *)(ulHandle) ); + ulHandle++; + SDL_AddAudioDevice( 1, &stLogDevice.szProductInfo, (void *)(ulHandle) ); + } +} + +static void OS2_WaitDevice(_THIS) +{ + PSDL_PrivateAudioData pAData = (PSDL_PrivateAudioData)this->hidden; + ULONG ulRC; + + /* Wait for an audio chunk to finish */ + ulRC = DosWaitEventSem( pAData->hevBuf, 5000 ); + if ( ulRC != NO_ERROR ) + debug( "DosWaitEventSem(), rc = %u", ulRC ); +} + +static Uint8 *OS2_GetDeviceBuf(_THIS) +{ + PSDL_PrivateAudioData pAData = (PSDL_PrivateAudioData)this->hidden; + + return pAData->aMixBuffers[pAData->ulNextBuf].pBuffer; +} + +static void OS2_PlayDevice(_THIS) +{ + PSDL_PrivateAudioData pAData = (PSDL_PrivateAudioData)this->hidden; + ULONG ulRC; + PMCI_MIX_BUFFER pMixBuffer = &pAData->aMixBuffers[pAData->ulNextBuf]; + + /* Queue it up */ +// lockIncr( (int *)&pAData->ulQueuedBuf ); + ulRC = pAData->stMCIMixSetup.pmixWrite( pAData->stMCIMixSetup.ulMixHandle, + pMixBuffer, 1 ); + if ( ulRC != MCIERR_SUCCESS ) + _mixIOError( "pmixWrite", ulRC ); + else + pAData->ulNextBuf = (pAData->ulNextBuf + 1) % pAData->cMixBuffers; +} + +static void OS2_WaitDone(_THIS) +{ + PSDL_PrivateAudioData pAData = (PSDL_PrivateAudioData)this->hidden; + + DosWaitEventSem( pAData->hevBuf, 3000 ); +} + +static void OS2_CloseDevice(_THIS) +{ + PSDL_PrivateAudioData pAData = (PSDL_PrivateAudioData)this->hidden; + MCI_GENERIC_PARMS sMCIGenericParms; + ULONG ulRC; + + if ( pAData == NULL ) + return; + + /* Close up audio */ + + if ( pAData->usDeviceId != (USHORT)~0 ) + { + // Device is open. + + if ( pAData->stMCIMixSetup.ulBitsPerSample != 0 ) + { + // Mixer was initialized. + ulRC = mciSendCommand( pAData->usDeviceId, MCI_MIXSETUP, + MCI_WAIT | MCI_MIXSETUP_DEINIT, + &pAData->stMCIMixSetup, 0 ); + if ( ulRC != MCIERR_SUCCESS ) + debug( "MCI_MIXSETUP, MCI_MIXSETUP_DEINIT - failed" ); + } + + if ( pAData->cMixBuffers != 0 ) + { + // Buffers was allocated. + MCI_BUFFER_PARMS stMCIBuffer; + + stMCIBuffer.ulBufferSize = pAData->aMixBuffers[0].ulBufferLength; + stMCIBuffer.ulNumBuffers = pAData->cMixBuffers; + stMCIBuffer.pBufList = &pAData->aMixBuffers; + + ulRC = mciSendCommand( pAData->usDeviceId, MCI_BUFFER, + MCI_WAIT | MCI_DEALLOCATE_MEMORY, &stMCIBuffer, 0 ); + if ( ulRC != MCIERR_SUCCESS ) + debug( "MCI_BUFFER, MCI_DEALLOCATE_MEMORY - failed" ); + } + + ulRC = mciSendCommand( pAData->usDeviceId, MCI_CLOSE, MCI_WAIT, + &sMCIGenericParms, 0 ); + if ( ulRC != MCIERR_SUCCESS ) + debug( "MCI_CLOSE - failed" ); + } + + if ( pAData->hevBuf != NULLHANDLE ) + DosCloseEventSem( pAData->hevBuf ); + + SDL_free( pAData ); + this->hidden = NULL; +} + +static int OS2_OpenDevice(_THIS, void *handle, const char *devname, + int iscapture) +{ + PSDL_PrivateAudioData pAData; + SDL_AudioFormat SDLAudioFmt; + MCI_AMP_OPEN_PARMS stMCIAmpOpen = { 0 }; + MCI_BUFFER_PARMS stMCIBuffer = { 0 }; + ULONG ulRC; + ULONG ulIdx; + + for( SDLAudioFmt = SDL_FirstAudioFormat( this->spec.format ); + SDLAudioFmt != 0; SDLAudioFmt = SDL_NextAudioFormat() ) + { + if ( ( SDLAudioFmt == AUDIO_U8 ) || ( SDLAudioFmt == AUDIO_S16 ) ) + break; + } + + if ( SDLAudioFmt == 0 ) + { + debug( "Unsupported audio format, AUDIO_S16 used" ); + SDLAudioFmt = AUDIO_S16; + this->spec.freq = AUDIO_S16; + } + + pAData = SDL_calloc( 1, sizeof(SDL_PrivateAudioData) ); + if ( pAData == NULL ) + return SDL_OutOfMemory(); + this->hidden = pAData; + + ulRC = DosCreateEventSem( NULL, &pAData->hevBuf, DCE_AUTORESET, TRUE ); + if ( ulRC != NO_ERROR ) + { + debug( "DosCreateEventSem() failed, rc = %u", ulRC ); + return -1; + } + + // Open audio device + stMCIAmpOpen.usDeviceID = handle != NULL ? ( ((ULONG)handle) - 1 ) : 0; + stMCIAmpOpen.pszDeviceType = (PSZ)MCI_DEVTYPE_AUDIO_AMPMIX; + ulRC = mciSendCommand( 0, MCI_OPEN, + _getEnvULong( "SDL_AUDIO_SHARE", 1, 0 ) != 0 + ? MCI_WAIT | MCI_OPEN_TYPE_ID | MCI_OPEN_SHAREABLE + : MCI_WAIT | MCI_OPEN_TYPE_ID, + &stMCIAmpOpen, 0 ); + if ( ulRC != MCIERR_SUCCESS ) + { + stMCIAmpOpen.usDeviceID = (USHORT)~0; + OS2_CloseDevice( this ); + return _MCIError( "MCI_OPEN", ulRC ); + } + pAData->usDeviceId = stMCIAmpOpen.usDeviceID; + + if ( iscapture != 0 ) + { + MCI_CONNECTOR_PARMS stMCIConnector = { 0 }; + MCI_AMP_SET_PARMS stMCIAmpSet = { 0 }; + BOOL fLineIn = _getEnvULong( "SDL_AUDIO_LINEIN", 1, 0 ); + + // Set particular connector. + stMCIConnector.ulConnectorType = fLineIn ? MCI_LINE_IN_CONNECTOR + : MCI_MICROPHONE_CONNECTOR; + mciSendCommand( stMCIAmpOpen.usDeviceID, MCI_CONNECTOR, + MCI_WAIT | MCI_ENABLE_CONNECTOR | + MCI_CONNECTOR_TYPE, &stMCIConnector, 0 ); + + // Disable monitor. + stMCIAmpSet.ulItem = MCI_AMP_SET_MONITOR; + mciSendCommand( stMCIAmpOpen.usDeviceID, MCI_SET, + MCI_WAIT | MCI_SET_OFF | MCI_SET_ITEM, + &stMCIAmpSet, 0 ); + + + // Set record volume. + stMCIAmpSet.ulLevel = _getEnvULong( "SDL_AUDIO_RECVOL", 100, 90 ); + stMCIAmpSet.ulItem = MCI_AMP_SET_AUDIO; + stMCIAmpSet.ulAudio = MCI_SET_AUDIO_ALL; // Both cnannels. + stMCIAmpSet.ulValue = fLineIn ? MCI_LINE_IN_CONNECTOR + : MCI_MICROPHONE_CONNECTOR ; + + mciSendCommand( stMCIAmpOpen.usDeviceID, MCI_SET, + MCI_WAIT | MCI_SET_AUDIO | MCI_AMP_SET_GAIN, + &stMCIAmpSet, 0 ); + } + + this->spec.format = SDLAudioFmt; + this->spec.channels = this->spec.channels > 1 ? 2 : 1; + if ( this->spec.freq < 8000 ) + this->spec.freq = 8000; + if ( this->spec.freq > 48000 ) + this->spec.freq = 48000; + + // Setup mixer. + pAData->stMCIMixSetup.ulFormatTag = MCI_WAVE_FORMAT_PCM; + pAData->stMCIMixSetup.ulBitsPerSample = SDL_AUDIO_BITSIZE( SDLAudioFmt ); + pAData->stMCIMixSetup.ulSamplesPerSec = this->spec.freq; + pAData->stMCIMixSetup.ulChannels = this->spec.channels; + pAData->stMCIMixSetup.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO; + if ( iscapture == 0 ) + { + pAData->stMCIMixSetup.ulFormatMode = MCI_PLAY; + pAData->stMCIMixSetup.pmixEvent = cbAudioWriteEvent; + } + else + { + pAData->stMCIMixSetup.ulFormatMode = MCI_RECORD; + pAData->stMCIMixSetup.pmixEvent = cbAudioReadEvent; + } + + ulRC = mciSendCommand( pAData->usDeviceId, MCI_MIXSETUP, + MCI_WAIT | MCI_MIXSETUP_INIT, &pAData->stMCIMixSetup, 0 ); + if ( ( ulRC != MCIERR_SUCCESS ) && ( this->spec.freq > 44100 ) ) + { + pAData->stMCIMixSetup.ulSamplesPerSec = 44100; + this->spec.freq = 44100; + ulRC = mciSendCommand( pAData->usDeviceId, MCI_MIXSETUP, + MCI_WAIT | MCI_MIXSETUP_INIT, &pAData->stMCIMixSetup, 0 ); + } + + debug( "Setup mixer [BPS: %u, Freq.: %u, Channels: %u]: %s", + pAData->stMCIMixSetup.ulBitsPerSample, + pAData->stMCIMixSetup.ulSamplesPerSec, + pAData->stMCIMixSetup.ulChannels, + ulRC == MCIERR_SUCCESS ? "SUCCESS" : "FAIL" ); + + if ( ulRC != MCIERR_SUCCESS ) + { + pAData->stMCIMixSetup.ulBitsPerSample = 0; + OS2_CloseDevice( this ); + return _MCIError( "MCI_MIXSETUP", ulRC ); + } + + this->spec.samples = pAData->stMCIMixSetup.ulSamplesPerSec; + /* Update the fragment size as size in bytes */ + SDL_CalculateAudioSpec( &this->spec ); + + // Allocate memory buffers + + stMCIBuffer.ulBufferSize = (this->spec.freq / 1000) * 100;// this->spec.size; + stMCIBuffer.ulNumBuffers = NUM_BUFFERS; + stMCIBuffer.pBufList = &pAData->aMixBuffers; + + ulRC = mciSendCommand( pAData->usDeviceId, MCI_BUFFER, + MCI_WAIT | MCI_ALLOCATE_MEMORY, &stMCIBuffer, 0 ); + if ( ulRC != MCIERR_SUCCESS ) + { + OS2_CloseDevice( this ); + return _MCIError( "MCI_BUFFER", ulRC ); + } + pAData->cMixBuffers = stMCIBuffer.ulNumBuffers; + this->spec.size = stMCIBuffer.ulBufferSize; + + // Fill all device buffers with data + + for( ulIdx = 0; ulIdx < stMCIBuffer.ulNumBuffers; ulIdx++ ) + { + pAData->aMixBuffers[ulIdx].ulFlags = 0; + pAData->aMixBuffers[ulIdx].ulBufferLength = stMCIBuffer.ulBufferSize; + pAData->aMixBuffers[ulIdx].ulUserParm = (ULONG)pAData; + + memset( ((PMCI_MIX_BUFFER)stMCIBuffer.pBufList)[ulIdx].pBuffer, + this->spec.silence, stMCIBuffer.ulBufferSize ); + } + + // Write buffers to kick off the amp mixer +// pAData->ulQueuedBuf = 1;//stMCIBuffer.ulNumBuffers; + ulRC = pAData->stMCIMixSetup.pmixWrite( pAData->stMCIMixSetup.ulMixHandle, + &pAData->aMixBuffers, + 1 );//stMCIBuffer.ulNumBuffers ); + if ( ulRC != MCIERR_SUCCESS ) + { + _mixIOError( "pmixWrite", ulRC ); + return -1; + } + + return 0; +} + + +static int OS2_Init(SDL_AudioDriverImpl * impl) +{ + /* Set the function pointers */ + impl->DetectDevices = OS2_DetectDevices; + impl->OpenDevice = OS2_OpenDevice; + impl->PlayDevice = OS2_PlayDevice; + impl->WaitDevice = OS2_WaitDevice; + impl->WaitDone = OS2_WaitDone; + impl->GetDeviceBuf = OS2_GetDeviceBuf; + impl->CloseDevice = OS2_CloseDevice; + +// [Digi]: SDL 2.0 does not support recording yet (2016-02-24). +// impl->HasCaptureSupport = SDL_TRUE; + + return 1; /* this audio target is available. */ +} + + +AudioBootStrap OS2AUDIO_bootstrap = { "MMOS2", "OS/2 DART", OS2_Init, 0 }; + +#endif /* SDL_AUDIO_DRIVER_OS2 */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/audio/os2/SDL_os2audio.h b/src/audio/os2/SDL_os2audio.h new file mode 100644 index 000000000..014e35ee5 --- /dev/null +++ b/src/audio/os2/SDL_os2audio.h @@ -0,0 +1,53 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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" + +#ifndef _SDL_os2mm_h +#define _SDL_os2mm_h + +#include "../SDL_sysaudio.h" + +#define INCL_OS2MM +#define INCL_PM +#define INCL_DOS +#define INCL_DOSERRORS +#include +#include + +/* Hidden "this" pointer for the audio functions */ +#define _THIS SDL_AudioDevice *this + +#define NUM_BUFFERS 3 + +typedef struct SDL_PrivateAudioData +{ + USHORT usDeviceId; + MCI_MIXSETUP_PARMS stMCIMixSetup; + HEV hevBuf; + ULONG ulNextBuf; + ULONG cMixBuffers; + MCI_MIX_BUFFER aMixBuffers[NUM_BUFFERS]; +// ULONG ulQueuedBuf; +} SDL_PrivateAudioData, *PSDL_PrivateAudioData; + +#endif /* _SDL_os2mm_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/core/os2/SDL_os2.c b/src/core/os2/SDL_os2.c new file mode 100644 index 000000000..d42e668cc --- /dev/null +++ b/src/core/os2/SDL_os2.c @@ -0,0 +1,36 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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 defined(__OS2__) + +#include "core/os2/geniconv/geniconv.h" + +// SDL_OS2Quit() will be called from SDL_QuitSubSystem(). + +void SDL_OS2Quit() +{ + // Unload DLL used for iconv. We can do it at any time and use iconv again - + // dynamic library will be loaded on first call iconv_open() (see geniconv). + libiconv_clean(); +} + +#endif diff --git a/src/core/os2/SDL_os2.h b/src/core/os2/SDL_os2.h new file mode 100644 index 000000000..a455c49e4 --- /dev/null +++ b/src/core/os2/SDL_os2.h @@ -0,0 +1,31 @@ +#ifndef _SDL_os2_h +#define _SDL_os2_h + +#include "SDL_log.h" +#include "SDL_stdinc.h" +#include ".\src\core\os2\geniconv\geniconv.h" + +#if OS2DEBUG==SDLOUTPUT + +# define debug(s,...) SDL_LogDebug( SDL_LOG_CATEGORY_APPLICATION, \ + __func__"(): "##s, ##__VA_ARGS__ ) + +#elif defined(OS2DEBUG) + +# define debug(s,...) printf( __func__"(): "##s"\n", ##__VA_ARGS__ ) + +#else + +# define debug(s,...) + +#endif // OS2DEBUG + + +// StrUTF8New() - geniconv\sys2utf8.c. +#define OS2_SysToUTF8(S) StrUTF8New( 1, S, SDL_strlen( S ) + 1 ) +#define OS2_UTF8ToSys(S) StrUTF8New( 0, (char *)(S), SDL_strlen( S ) + 1 ) + +// SDL_OS2Quit() will be called from SDL_QuitSubSystem(). +void SDL_OS2Quit(); + +#endif // _SDL_os2_h diff --git a/src/core/os2/geniconv/geniconv.c b/src/core/os2/geniconv/geniconv.c new file mode 100644 index 000000000..b82e903d1 --- /dev/null +++ b/src/core/os2/geniconv/geniconv.c @@ -0,0 +1,143 @@ +/* + Universal iconv implementation for OS/2. + + Andrey Vasilkin, 2016. +*/ + +#define INCL_DOSMODULEMGR /* Module Manager values */ +#define INCL_DOSERRORS /* Error values */ +#include +#include + +//#define DEBUG + +#ifdef DEBUG +# include +# define debug(s,...) printf(__func__"(): "##s"\n" ,##__VA_ARGS__) +#else +# define debug(s,...) +#endif + +// Exports from os2iconv.c. +extern iconv_t _System os2_iconv_open(const char* tocode, const char* fromcode); +extern size_t _System os2_iconv(iconv_t cd, char* * inbuf, + size_t *inbytesleft, char* * outbuf, + size_t *outbytesleft); +extern int _System os2_iconv_close(iconv_t cd); + +// Functions pointers types. +typedef iconv_t _System (*FNICONV_OPEN)(const char* tocode, const char* fromcode); +typedef size_t _System (*FNICONV)(iconv_t cd, char* * inbuf, + size_t *inbytesleft, char* * outbuf, + size_t *outbytesleft); +typedef int _System (*FNICONV_CLOSE)(iconv_t cd); + +// Used DLL module handle. +static HMODULE hmIconv = NULLHANDLE; +// Functions pointers. +static FNICONV_OPEN fn_iconv_open = NULL; +static FNICONV fn_iconv = NULL; +static FNICONV_CLOSE fn_iconv_close = NULL; + + +static BOOL _loadDLL(PSZ pszName, PSZ pszIconvOpen, PSZ pszIconv, + PSZ pszIconvClose) +{ + ULONG ulRC; + CHAR acError[256]; + + ulRC = DosLoadModule( &acError, sizeof(acError), pszName, &hmIconv ); + if ( ulRC != NO_ERROR ) + { + debug( "DLL not loaded: %s", &acError ); + return FALSE; + } + + do + { + ulRC = DosQueryProcAddr( hmIconv, 0, pszIconvOpen, (PFN *)&fn_iconv_open ); + if ( ulRC != NO_ERROR ) + { + debug( "Error: cannot find entry %s in %s", pszIconvOpen, pszName ); + break; + } + + ulRC = DosQueryProcAddr( hmIconv, 0, pszIconv, (PFN *)&fn_iconv ); + if ( ulRC != NO_ERROR ) + { + debug( "Error: cannot find entry %s in %s", pszIconv, pszName ); + break; + } + + ulRC = DosQueryProcAddr( hmIconv, 0, pszIconvClose, (PFN *)&fn_iconv_close ); + if ( ulRC != NO_ERROR ) + { + debug( "Error: cannot find entry %s in %s", pszIconvClose, pszName ); + break; + } + + debug( "DLL %s used", pszName ); + return TRUE; + } + while( FALSE ); + + DosFreeModule( hmIconv ); + hmIconv = NULLHANDLE; + return FALSE; +} + +static void _init() +{ + if ( fn_iconv_open != NULL ) + // Already was initialized. + return; + + // Try to load kiconv.dll, iconv2.dll or iconv.dll. + if ( !_loadDLL( "KICONV", "_libiconv_open", "_libiconv", "_libiconv_close" ) + && !_loadDLL( "ICONV2", "_libiconv_open", "_libiconv", "_libiconv_close" ) + && !_loadDLL( "ICONV", "_iconv_open", "_iconv", "_iconv_close" ) ) + { + // No one DLL was loaded - use OS/2 conversion objects API. + + debug( "Uni*() API used" ); + fn_iconv_open = os2_iconv_open; + fn_iconv = os2_iconv; + fn_iconv_close = os2_iconv_close; + } +} + + + +// Public routines. +// ---------------- + +// Non-standard function for iconv to unload the used dynamic library. +void libiconv_clean() +{ + if ( hmIconv != NULLHANDLE ) + { + DosFreeModule( hmIconv ); + hmIconv = NULLHANDLE; + + fn_iconv_open = NULL; + fn_iconv = NULL; + fn_iconv_close = NULL; + } +} + +iconv_t libiconv_open(const char* tocode, const char* fromcode) +{ + _init(); + return fn_iconv_open( tocode, fromcode ); +} + +size_t libiconv(iconv_t cd, char* * inbuf, size_t *inbytesleft, + char* * outbuf, size_t *outbytesleft) +{ + return fn_iconv( cd, inbuf, inbytesleft, outbuf, outbytesleft ); +} + +int libiconv_close(iconv_t cd) +{ + return fn_iconv_close( cd ); +} diff --git a/src/core/os2/geniconv/geniconv.h b/src/core/os2/geniconv/geniconv.h new file mode 100644 index 000000000..e22ce640d --- /dev/null +++ b/src/core/os2/geniconv/geniconv.h @@ -0,0 +1,59 @@ +/* + Universal iconv implementation for OS/2. + + Andrey Vasilkin, 2016. +*/ + +#ifndef GENICONV_H +#define GENICONV_H + +#include + +#ifdef iconv_open +#undef iconv_open +#endif +#define iconv_open libiconv_open + +#ifdef iconv +#undef iconv +#endif +#define iconv libiconv + +#ifdef iconv_close +#undef iconv_close +#endif +#define iconv_close libiconv_close + +#define iconv_clean libiconv_clean + +// Non-standard function for iconv to unload the used dynamic library. +void libiconv_clean(); + +iconv_t libiconv_open(const char* tocode, const char* fromcode); +size_t libiconv(iconv_t cd, char* * inbuf, size_t *inbytesleft, + char* * outbuf, size_t *outbytesleft); +int libiconv_close(iconv_t cd); + +// System codepage <-> UTF-8. + +// StrUTF8() +// Coverts string from system cp. to UTF-8 (fToUTF8 is not 0) or from UTF-8 to +// the system cp. (fToUTF8 is 0). Converted ASCIIZ string will be placed at the +// buffer pcDst, up to cbDst - 1 (for sys->utf8) or 2 (for utf8->sys) bytes. +// Returns the number of bytes written into pcDst, not counting the terminating +// 0 byte(s) or -1 on error. +int StrUTF8(int fToUTF8, char *pcDst, int cbDst, char *pcSrc, int cbSrc); + +// StrUTF8New() +// Coverts string from system cp. to UTF-8 (fToUTF8 is not 0) or from UTF-8 to +// the system cp. (fToUTF8 is 0). Memory for the new string is obtained by +// using libc malloc(). +// Returns converted string, terminating two bytes 0 is appended to the result. +// Returns null on error. +char *StrUTF8New(int fToUTF8, char *pcStr, int cbStr); + +// StrUTF8Free() +// Deallocates the memory block located by StrUTF8New() (just libc free()). +void StrUTF8Free(char *pszStr); + +#endif // GENICONV_H diff --git a/src/core/os2/geniconv/iconv.h b/src/core/os2/geniconv/iconv.h new file mode 100644 index 000000000..b336dabe3 --- /dev/null +++ b/src/core/os2/geniconv/iconv.h @@ -0,0 +1,21 @@ +#ifndef ICONV_H_ /* minimal iconv.h header based on public knowledge */ +#define ICONV_H_ + +#include /* size_t */ +#include + +typedef void *iconv_t; + +#ifdef __cplusplus +extern "C" { +#endif + +extern iconv_t iconv_open(const char *, const char *); +extern size_t iconv(iconv_t, char **, size_t *, char **, size_t *); +extern int iconv_close(iconv_t); + +#ifdef __cplusplus +} +#endif + +#endif /* ICONV_H_ */ diff --git a/src/core/os2/geniconv/makefile b/src/core/os2/geniconv/makefile new file mode 100644 index 000000000..7dffd30c3 --- /dev/null +++ b/src/core/os2/geniconv/makefile @@ -0,0 +1,37 @@ +# +# Universal iconv implementation for OS/2. +# +# OpenWatcom makefile to build a library that uses kiconv.dll / iconv2.dll / +# iconv.dll or OS/2 Uni*() API. +# +# Andrey Vasilkin, 2016. +# + +LIBFILE = geniconv.lib + +all: $(LIBFILE) test.exe .symbolic + +CFLAGS = -I$(%WATCOM)/h/os2 -I$(%WATCOM)/h -I. -bt=os2 -q -d0 -w2 + +SRCS = geniconv.c os2cp.c os2iconv.c +SRCS+= sys2utf8.c + +OBJS = $(SRCS:.c=.obj) + +LIBS = libuls.lib libconv.lib $(LIBFILE) + +test.exe: $(LIBFILE) test.obj + wlink op quiet system os2v2 file test.obj lib {$(LIBS)} name $* + +$(LIBFILE): $(OBJS) + @if exist $@ rm $@ + @for %f in ($(OBJS)) do wlib -q -b $* +%f + +.c.obj: + wcc386 $(CFLAGS) -fo=$^@ $< + +clean: .SYMBOLIC + @if exist *.obj rm *.obj + @if exist *.err rm *.err + @if exist $(LIBFILE) rm $(LIBFILE) + @if exist test.exe rm test.exe diff --git a/src/core/os2/geniconv/os2cp.c b/src/core/os2/geniconv/os2cp.c new file mode 100644 index 000000000..dd9e83a91 --- /dev/null +++ b/src/core/os2/geniconv/os2cp.c @@ -0,0 +1,383 @@ +#include "os2cp.h" +#define INCL_DOSNLS +#define INCL_DOSERRORS +#include +#include +#include + +typedef struct _CP2NAME { + ULONG ulCode; + PSZ pszName; +} CP2NAME; + +typedef struct _NAME2CP { + PSZ pszName; + ULONG ulCode; +} NAME2CP; + +static CP2NAME aCP2Name[] = +{ + {367, "ANSI_X3.4-1968"}, + {813, "ECMA-118"}, + {819, "CP819"}, + {850, "850"}, + {862, "862"}, + {866, "866"}, + {874, "ISO-IR-166"}, + {878, "KOI8-R"}, + {896, "JISX0201-1976"}, + {901, "ISO-8859-13"}, + {912, "ISO-8859-2"}, + {913, "ISO-8859-3"}, + {914, "ISO-8859-4"}, + {915, "CYRILLIC"}, + {920, "ISO-8859-9"}, + {923, "ISO-8859-15"}, + {943, "MS_KANJI"}, + {954, "EUC-JP"}, + {964, "EUC-TW"}, + {970, "EUC-KR"}, + {1051, "HP-ROMAN8"}, + {1089, "ARABIC"}, + {1129, "VISCII"}, + {1168, "KOI8-U"}, + {1200, "ISO-10646-UCS-2"}, + {1202, "UTF-16LE"}, + {1204, "UCS-2BE"}, + {1208, "UTF-8"}, + {1232, "UTF-32BE"}, + {1234, "UTF-32LE"}, + {1236, "ISO-10646-UCS-4"}, + {1250, "CP1250"}, + {1251, "CP1251"}, + {1252, "CP1252"}, + {1253, "CP1253"}, + {1254, "CP1254"}, + {1255, "CP1255"}, + {1256, "CP1256"}, + {1257, "CP1257"}, + {1275, "MAC"}, + {1383, "CN-GB"}, + {1386, "GBK"}, + {1392, "GB18030"}, + {62210, "HEBREW"} +}; + +static NAME2CP aName2CP[] = +{ + {"850", 850}, + {"862", 862}, + {"866", 866}, + {"ANSI_X3.4-1968", 367}, + {"ANSI_X3.4-1986", 367}, + {"ARABIC", 1089}, + {"ASCII", 367}, + {"ASMO-708", 1089}, + {"CN-GB", 1383}, + {"CP1250", 1250}, + {"CP1251", 1251}, + {"CP1252", 1252}, + {"CP1253", 1253}, + {"CP1254", 1254}, + {"CP1255", 1255}, + {"CP1256", 1256}, + {"CP1257", 1257}, + {"CP367", 367}, + {"CP819", 819}, + {"CP850", 850}, + {"CP862", 862}, + {"CP866", 866}, + {"CP936", 1386}, + {"CSASCII", 367}, + {"CSEUCKR", 970}, + {"CSEUCPKDFMTJAPANESE", 954}, + {"CSEUCTW", 964}, + {"CSGB2312", 1383}, + {"CSHALFWIDTHKATAKANA", 896}, + {"CSHPROMAN8", 1051}, + {"CSIBM866", 866}, + {"CSISOLATIN1", 819}, + {"CSISOLATIN2", 912}, + {"CSISOLATIN3", 913}, + {"CSISOLATIN4", 914}, + {"CSISOLATIN5", 920}, + {"CSISOLATINARABIC", 1089}, + {"CSISOLATINCYRILLIC", 915}, + {"CSISOLATINGREEK", 813}, + {"CSISOLATINHEBREW", 62210}, + {"CSKOI8R", 878}, + {"CSKSC56011987", 970}, + {"CSMACINTOSH", 1275}, + {"CSPC850MULTILINGUAL", 850}, + {"CSPC862LATINHEBREW", 862}, + {"CSSHIFTJIS", 943}, + {"CSUCS4", 1236}, + {"CSUNICODE", 1200}, + {"CSUNICODE11", 1204}, + {"CSVISCII", 1129}, + {"CYRILLIC", 915}, + {"ECMA-114", 1089}, + {"ECMA-118", 813}, + {"ELOT_928", 813}, + {"EUC-CN", 1383}, + {"EUC-JP", 954}, + {"EUC-KR", 970}, + {"EUC-TW", 964}, + {"EUCCN", 1383}, + {"EUCJP", 954}, + {"EUCKR", 970}, + {"EUCTW", 964}, + {"EXTENDED_UNIX_CODE_PACKED_FORMAT_FOR_JAPANESE", 954}, + {"GB18030", 1392}, + {"GB2312", 1383}, + {"GBK", 1386}, + {"GREEK", 813}, + {"GREEK8", 813}, + {"HEBREW", 62210}, + {"HP-ROMAN8", 1051}, + {"IBM367", 367}, + {"IBM819", 819}, + {"IBM850", 850}, + {"IBM862", 862}, + {"IBM866", 866}, + {"ISO-10646-UCS-2", 1200}, + {"ISO-10646-UCS-4", 1236}, + {"ISO-8859-1", 819}, + {"ISO-8859-13", 901}, + {"ISO-8859-15", 923}, + {"ISO-8859-2", 912}, + {"ISO-8859-3", 913}, + {"ISO-8859-4", 914}, + {"ISO-8859-5", 915}, + {"ISO-8859-6", 1089}, + {"ISO-8859-7", 813}, + {"ISO-8859-8", 62210}, + {"ISO-8859-9", 920}, + {"ISO-IR-100", 819}, + {"ISO-IR-101", 912}, + {"ISO-IR-109", 913}, + {"ISO-IR-110", 914}, + {"ISO-IR-126", 813}, + {"ISO-IR-127", 1089}, + {"ISO-IR-138", 62210}, + {"ISO-IR-144", 915}, + {"ISO-IR-148", 920}, + {"ISO-IR-149", 970}, + {"ISO-IR-166", 874}, + {"ISO-IR-179", 901}, + {"ISO-IR-203", 923}, + {"ISO-IR-6", 367}, + {"ISO646-US", 367}, + {"ISO8859-1", 819}, + {"ISO8859-13", 901}, + {"ISO8859-15", 923}, + {"ISO8859-2", 912}, + {"ISO8859-3", 913}, + {"ISO8859-4", 914}, + {"ISO8859-5", 915}, + {"ISO8859-6", 1089}, + {"ISO8859-7", 813}, + {"ISO8859-8", 62210}, + {"ISO8859-9", 920}, + {"ISO_646.IRV:1991", 367}, + {"ISO_8859-1", 819}, + {"ISO_8859-13", 901}, + {"ISO_8859-15", 923}, + {"ISO_8859-15:1998", 923}, + {"ISO_8859-1:1987", 819}, + {"ISO_8859-2", 912}, + {"ISO_8859-2:1987", 912}, + {"ISO_8859-3", 913}, + {"ISO_8859-3:1988", 913}, + {"ISO_8859-4", 914}, + {"ISO_8859-4:1988", 914}, + {"ISO_8859-5", 915}, + {"ISO_8859-5:1988", 915}, + {"ISO_8859-6", 1089}, + {"ISO_8859-6:1987", 1089}, + {"ISO_8859-7", 813}, + {"ISO_8859-7:1987", 813}, + {"ISO_8859-7:2003", 813}, + {"ISO_8859-8", 62210}, + {"ISO_8859-8:1988", 62210}, + {"ISO_8859-9", 920}, + {"ISO_8859-9:1989", 920}, + {"JISX0201-1976", 896}, + {"JIS_X0201", 896}, + {"KOI8-R", 878}, + {"KOI8-U", 1168}, + {"KOREAN", 970}, + {"KSC_5601", 970}, + {"KS_C_5601-1987", 970}, + {"KS_C_5601-1989", 970}, + {"L1", 819}, + {"L2", 912}, + {"L3", 913}, + {"L4", 914}, + {"L5", 920}, + {"L7", 901}, + {"LATIN-9", 923}, + {"LATIN1", 819}, + {"LATIN2", 912}, + {"LATIN3", 913}, + {"LATIN4", 914}, + {"LATIN5", 920}, + {"LATIN7", 901}, + {"MAC", 1275}, + {"MACINTOSH", 1275}, + {"MACROMAN", 1275}, + {"MS-ANSI", 1252}, + {"MS-ARAB", 1256}, + {"MS-CYRL", 1251}, + {"MS-EE", 1250}, + {"MS-GREEK", 1253}, + {"MS-HEBR", 1255}, + {"MS-TURK", 1254}, + {"MS936", 1386}, + {"MS_KANJI", 943}, + {"R8", 1051}, + {"ROMAN8", 1051}, + {"SHIFT-JIS", 943}, + {"SHIFT_JIS", 943}, + {"SJIS", 943}, + {"TIS-620", 874}, + {"TIS620", 874}, + {"TIS620-0", 874}, + {"TIS620.2529-1", 874}, + {"TIS620.2533-0", 874}, + {"TIS620.2533-1", 874}, + {"UCS-2", 1200}, + {"UCS-2BE", 1204}, + {"UCS-4", 1236}, + {"UNICODE-1-1", 1204}, + {"UNICODEBIG", 1204}, + {"US", 367}, + {"US-ASCII", 367}, + {"UTF-16", 1204}, + {"UTF-16BE", 1200}, + {"UTF-16LE", 1202}, + {"UTF-32", 1236}, + {"UTF-32BE", 1232}, + {"UTF-32LE", 1234}, + {"UTF-8", 1208}, + {"VISCII", 1129}, + {"VISCII1.1-1", 1129}, + {"WINBALTRIM", 1257}, + {"WINDOWS-1250", 1250}, + {"WINDOWS-1251", 1251}, + {"WINDOWS-1252", 1252}, + {"WINDOWS-1253", 1253}, + {"WINDOWS-1254", 1254}, + {"WINDOWS-1255", 1255}, + {"WINDOWS-1256", 1256}, + {"WINDOWS-1257", 1257}, + {"WINDOWS-936", 1386}, + {"X0201", 896} +}; + +char * os2cpToName(unsigned long cp) +{ + ULONG ulLo = 0; + ULONG ulHi = ( sizeof(aCP2Name) / sizeof(struct _CP2NAME) ) - 1; + ULONG ulNext; + LONG lFound = -1; + + if ( cp == SYSTEM_CP ) + { + ULONG aulCP[3]; + ULONG cCP; + + if ( DosQueryCp( sizeof(aulCP), &aulCP, &cCP ) != NO_ERROR ) + return NULL; + + cp = aulCP[0]; + } + + if ( ( aCP2Name[0].ulCode > cp ) || ( aCP2Name[ulHi].ulCode < cp ) ) + return NULL; + + if ( aCP2Name[0].ulCode == cp ) + return aCP2Name[0].pszName; + + if ( aCP2Name[ulHi].ulCode == cp ) + return aCP2Name[ulHi].pszName; + + while( ( ulHi - ulLo ) > 1 ) + { + ulNext = ( ulLo + ulHi ) / 2; + + if ( aCP2Name[ulNext].ulCode < cp ) + ulLo = ulNext; + else if ( aCP2Name[ulNext].ulCode > cp ) + ulHi = ulNext; + else + { + lFound = ulNext; + break; + } + } + + return lFound == -1 ? NULL : aCP2Name[lFound].pszName; +} + +unsigned long os2cpFromName(char *cp) +{ + ULONG ulLo = 0; + ULONG ulHi = ( sizeof(aName2CP) / sizeof(struct _NAME2CP) ) - 1; + ULONG ulNext; + LONG lFound = -1; + LONG lCmp; + PCHAR pcEnd; + CHAR acBuf[64]; + + if ( cp == NULL ) + { + ULONG aulCP[3]; + ULONG cCP; + + return DosQueryCp( sizeof(aulCP), &aulCP, &cCP ) != NO_ERROR ? 0 : aulCP[0]; + } + + while( isspace( *cp ) ) cp++; + pcEnd = strchr( cp, ' ' ); + if ( pcEnd == NULL ) + pcEnd = strchr( cp, '\0' ); + + ulNext = pcEnd - cp; + if ( ulNext >= sizeof(acBuf) ) + return 0; + + memcpy( &acBuf, cp, ulNext ); + acBuf[ulNext] = '\0'; + strupr( &acBuf ); + + lCmp = strcmp( aName2CP[0].pszName, &acBuf ); + if ( lCmp > 0 ) + return 0; + else if ( lCmp == 0 ) + return aName2CP[0].ulCode; + + lCmp = strcmp( aName2CP[ulHi].pszName, &acBuf ); + if ( lCmp < 0 ) + return 0; + else if ( lCmp == 0 ) + return aName2CP[ulHi].ulCode; + + while( ( ulHi - ulLo ) > 1 ) + { + ulNext = ( ulLo + ulHi ) / 2; + + lCmp = strcmp( aName2CP[ulNext].pszName, &acBuf ); + if ( lCmp < 0 ) + ulLo = ulNext; + else if ( lCmp > 0 ) + ulHi = ulNext; + else + { + lFound = ulNext; + break; + } + } + + return lFound == -1 ? 0 : aName2CP[lFound].ulCode; +} diff --git a/src/core/os2/geniconv/os2cp.h b/src/core/os2/geniconv/os2cp.h new file mode 100644 index 000000000..542b41eb0 --- /dev/null +++ b/src/core/os2/geniconv/os2cp.h @@ -0,0 +1,9 @@ +#ifndef OS2CP_H +#define OS2CP_H 1 + +#define SYSTEM_CP 0 + +char * os2cpToName(unsigned long cp); +unsigned long os2cpFromName(char *cp); + +#endif // OS2CP_H diff --git a/src/core/os2/geniconv/os2iconv.c b/src/core/os2/geniconv/os2iconv.c new file mode 100644 index 000000000..1e2ba2457 --- /dev/null +++ b/src/core/os2/geniconv/os2iconv.c @@ -0,0 +1,264 @@ +/* + Implementation iconv via OS/2 conversion objects API. + + Andrey Vasilkin. +*/ + +#define ICONV_THREAD_SAFE 1 +//#undef ICONV_THREAD_SAFE + +#include "iconv.h" +#include +#include +#include +#ifdef ICONV_THREAD_SAFE +#define INCL_DOSSEMAPHORES +#define INCL_DOSERRORS +#include +#endif +#include "os2cp.h" + +#define MAX_CP_NAME_LEN 64 + +typedef struct iuconv_obj { + UconvObject uo_tocode; + UconvObject uo_fromcode; + int buf_len; + UniChar *buf; +#ifdef ICONV_THREAD_SAFE + HMTX hMtx; +#endif +} iuconv_obj; + + +static int _createUconvObj(const char *code, UconvObject *uobj) +{ + UniChar uc_code[MAX_CP_NAME_LEN]; + int i; + const char *ch = code; + + if ( code == NULL ) + uc_code[0] = 0; + else + { + for( i = 0; i < MAX_CP_NAME_LEN; i++ ) + { + uc_code[i] = (unsigned short)*ch; + if ( !(*ch) ) break; + ch++; + } + } + + return UniCreateUconvObject( &uc_code, uobj ); +} + +static int uconv_open(const char *code, UconvObject *uobj) +{ + int rc; + + if ( !stricmp( code, "UTF-16" ) ) + { + *uobj = NULL; + return ULS_SUCCESS; + } + + rc = _createUconvObj( code, uobj ); + if ( rc != ULS_SUCCESS ) + { + unsigned long cp = os2cpFromName( (char *)code ); + char cp_name[16]; + + if ( cp != 0 && _snprintf( &cp_name, sizeof(cp_name), "IBM-%u", cp ) > 0 ) + rc = _createUconvObj( &cp_name, uobj ); + } + + return rc; +} + + +extern iconv_t _System os2_iconv_open(const char* tocode, const char* fromcode) +{ + UconvObject uo_tocode; + UconvObject uo_fromcode; + int rc; + iuconv_obj *iuobj; + + if ( tocode == NULL ) + tocode = ""; + + if ( fromcode == NULL ) + fromcode = ""; + + if ( stricmp(tocode, fromcode) != 0 ) + { + rc = uconv_open( fromcode, &uo_fromcode ); + if ( rc != ULS_SUCCESS ) + { + errno = EINVAL; + return (iconv_t)(-1); + } + + rc = uconv_open( tocode, &uo_tocode ); + if ( rc != ULS_SUCCESS ) + { + UniFreeUconvObject( uo_fromcode ); + errno = EINVAL; + return (iconv_t)(-1); + } + } + else { + uo_tocode = NULL; + uo_fromcode = NULL; + } + + iuobj = malloc( sizeof(iuconv_obj) ); + iuobj->uo_tocode = uo_tocode; + iuobj->uo_fromcode = uo_fromcode; + iuobj->buf_len = 0; + iuobj->buf = NULL; +#ifdef ICONV_THREAD_SAFE + DosCreateMutexSem( NULL, &iuobj->hMtx, 0, FALSE ); +#endif + + return iuobj; +} + +extern size_t _System os2_iconv(iconv_t cd, char* * inbuf, + size_t *inbytesleft, + char* * outbuf, size_t *outbytesleft) +{ + UconvObject uo_tocode = ((iuconv_obj *)(cd))->uo_tocode; + UconvObject uo_fromcode = ((iuconv_obj *)(cd))->uo_fromcode; + size_t nonIdenticalConv = 0; + UniChar *uc_buf; + size_t uc_buf_len; + UniChar **uc_str; + size_t *uc_str_len; + int rc; + size_t ret = (size_t)(-1); + + if ( uo_tocode == NULL && uo_fromcode == NULL ) + { + uc_buf_len = min( *inbytesleft, *outbytesleft ); + memcpy( *outbuf, *inbuf, uc_buf_len ); + *inbytesleft -= uc_buf_len; + *outbytesleft -= uc_buf_len; + outbuf += uc_buf_len; + inbuf += uc_buf_len; + return uc_buf_len; + } + +#ifdef ICONV_THREAD_SAFE + DosRequestMutexSem( ((iuconv_obj *)(cd))->hMtx, SEM_INDEFINITE_WAIT ); +#endif + + if ( uo_tocode && uo_fromcode && + (( ((iuconv_obj *)(cd))->buf_len >> 1 ) < (*inbytesleft)) ) + { + if ( ( ((iuconv_obj *)(cd))->buf ) != NULL ) + free( ((iuconv_obj *)(cd))->buf ); + ((iuconv_obj *)(cd))->buf_len = *inbytesleft << 1; + ((iuconv_obj *)(cd))->buf = (UniChar *)malloc( ((iuconv_obj *)(cd))->buf_len ); + } + + if ( uo_fromcode ) + { + if ( uo_tocode ) + { + uc_buf = ((iuconv_obj *)(cd))->buf; + uc_buf_len = ((iuconv_obj *)(cd))->buf_len; + uc_str = &uc_buf; + } + else { + uc_str = (UniChar **)outbuf; + uc_buf_len = *outbytesleft; + } + uc_buf_len = uc_buf_len >> 1; + uc_str_len = &uc_buf_len; + rc = UniUconvToUcs( uo_fromcode, (void **)inbuf, inbytesleft, + uc_str, uc_str_len, &nonIdenticalConv ); + uc_buf_len = uc_buf_len << 1; + if ( !uo_tocode ) + *outbytesleft = uc_buf_len; + + if ( rc != ULS_SUCCESS ) + { + errno = EILSEQ; + goto done; + } + else + if ( *inbytesleft && !*uc_str_len ) + { + errno = E2BIG; + goto done; + } + + if ( !uo_tocode ) + return nonIdenticalConv; + + uc_buf = ((iuconv_obj *)(cd))->buf; + uc_buf_len = ((iuconv_obj *)(cd))->buf_len - uc_buf_len; + uc_str = &uc_buf; + uc_str_len = &uc_buf_len; + } + else { + uc_str = (UniChar **)inbuf; + uc_str_len = inbytesleft; + } + + *uc_str_len = *uc_str_len>>1; + rc = UniUconvFromUcs( uo_tocode, uc_str, uc_str_len, (void **)outbuf, + outbytesleft, &nonIdenticalConv ); + if ( rc != ULS_SUCCESS ) + { + switch ( rc ) + { + case ULS_BUFFERFULL: + errno = E2BIG; + break; + case ULS_ILLEGALSEQUENCE: + errno = EILSEQ; + break; + case ULS_INVALID: + errno = EINVAL; + break; + } + goto done; + } + else + if ( *uc_str_len && !*outbytesleft ) + { + errno = E2BIG; + goto done; + } + + ret = nonIdenticalConv; + +done: + +#ifdef ICONV_THREAD_SAFE + DosReleaseMutexSem( ((iuconv_obj *)(cd))->hMtx ); +#endif + return ret; +} + +extern int _System os2_iconv_close(iconv_t cd) +{ + if ( !cd ) + return 0; + +#ifdef ICONV_THREAD_SAFE + DosCloseMutexSem( ((iuconv_obj *)(cd))->hMtx ); +#endif + if ( ((iuconv_obj *)(cd))->uo_tocode != NULL ) + UniFreeUconvObject( ((iuconv_obj *)(cd))->uo_tocode ); + if ( ((iuconv_obj *)(cd))->uo_fromcode != NULL ) + UniFreeUconvObject( ((iuconv_obj *)(cd))->uo_fromcode ); + + if ( ( ((iuconv_obj *)(cd))->buf ) != NULL ) + free( ((iuconv_obj *)(cd))->buf ); + + free(cd); + + return 0; +} diff --git a/src/core/os2/geniconv/sys2utf8.c b/src/core/os2/geniconv/sys2utf8.c new file mode 100644 index 000000000..51ce4a146 --- /dev/null +++ b/src/core/os2/geniconv/sys2utf8.c @@ -0,0 +1,97 @@ +#include +#include + +int StrUTF8(int fToUTF8, char *pcDst, int cbDst, char *pcSrc, int cbSrc) +{ + size_t rc; + char *pcDstStart = pcDst; + iconv_t cd; + char *pszToCP, *pszFromCP; + int fError = 0; + + if ( cbDst < 4 ) + return -1; + + if ( fToUTF8 ) + { + pszToCP = "UTF-8"; + pszFromCP = ""; + } + else + { + pszToCP = ""; + pszFromCP = "UTF-8"; + } + + cd = iconv_open( pszToCP, pszFromCP ); + if ( cd == (iconv_t)-1 ) + return -1; + + while( cbSrc > 0 ) + { + rc = iconv( cd, &pcSrc, (size_t *)&cbSrc, &pcDst, (size_t *)&cbDst ); + if ( rc == (size_t)-1 ) + { + if ( errno == EILSEQ ) + { + // Try to skip invalid character. + pcSrc++; + cbSrc--; + continue; + } + + fError = 1; + break; + } + } + + iconv_close( cd ); + + // Write trailing ZERO (1 byte for UTF-8, 2 bytes for the system cp.). + + if ( fToUTF8 ) + { + if ( cbDst < 1 ) + { + pcDst--; + fError = 1; // The destination buffer overflow. + } + *pcDst = '\0'; + } + else + { + if ( cbDst < 2 ) + { + pcDst -= ( cbDst == 0 ) ? 2 : 1; + fError = 1; // The destination buffer overflow. + } + *((short *)pcDst) = '\0'; + } + + return fError ? -1 : ( pcDst - pcDstStart ); +} + +char *StrUTF8New(int fToUTF8, char *pcStr, int cbStr) +{ + int cbNewStr = ( ( cbStr > 4 ? cbStr : 4 ) + 1 ) * 2; + char *pszNewStr = malloc( cbNewStr ); + + if ( pszNewStr == NULL ) + return NULL; + + cbNewStr = StrUTF8( fToUTF8, pszNewStr, cbNewStr, pcStr, cbStr ); + if ( cbNewStr != -1 ) + { + pcStr = realloc( pszNewStr, cbNewStr + ( fToUTF8 ? 1 : sizeof(short) ) ); + if ( pcStr != NULL ) + return pcStr; + } + + free( pszNewStr ); + return NULL; +} + +void StrUTF8Free(char *pszStr) +{ + free( pszStr ); +} diff --git a/src/core/os2/geniconv/test.c b/src/core/os2/geniconv/test.c new file mode 100644 index 000000000..efd0b95b7 --- /dev/null +++ b/src/core/os2/geniconv/test.c @@ -0,0 +1,45 @@ +#include +#include +#include + +void main() +{ + char acBuf[128]; + char *inbuf = "Тест - проверка"; // KOI8-R string. + size_t inbytesleft = strlen( inbuf ); + char *outbuf = &acBuf; + size_t outbytesleft = sizeof( acBuf ); + iconv_t ic; + + // KOI8 -> system cp. + + ic = iconv_open( "", "KOI8-R" ); + if ( ic == (iconv_t)(-1) ) + { + puts( "iconv_open() fail" ); + return; + } + + iconv( ic, &inbuf, &inbytesleft, &outbuf, &outbytesleft ); + printf( "KOI8-R to system cp.: %s\n", &acBuf ); + + iconv_close( ic ); + + // System cp. -> UTF-8 -> system cp. + + // System cp. -> UTF-8 by StrUTF8New(). + inbuf = StrUTF8New( 1, &acBuf, strlen( &acBuf ) ); + + // UTF-8 -> system cp. by StrUTF8(). + if ( StrUTF8( 0, &acBuf, sizeof(acBuf), inbuf, strlen( inbuf ) ) == -1 ) + puts( "StrUTF8() failed" ); + else + printf( "system cp. -> UTF-8 -> system cp.: %s\n", &acBuf ); + + free( inbuf ); + + // Unload used DLL. + iconv_clean(); + + puts( "Done." ); +} diff --git a/src/filesystem/os2/SDL_sysfilesystem.c b/src/filesystem/os2/SDL_sysfilesystem.c new file mode 100644 index 000000000..2420ae2ca --- /dev/null +++ b/src/filesystem/os2/SDL_sysfilesystem.c @@ -0,0 +1,122 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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" + +#ifdef SDL_FILESYSTEM_OS2 + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* System dependent filesystem routines */ + +#include "SDL_error.h" +#include "SDL_filesystem.h" +#include "../../core/os2/SDL_os2.h" + +#include +#include +#define INCL_DOSPROCESS +#define INCL_DOSERRORS +#include + + +char * +SDL_GetBasePath(void) +{ + PTIB tib; + PPIB pib; + ULONG ulRC = DosGetInfoBlocks( &tib, &pib ); + PCHAR pcEnd; + ULONG cbResult; + CHAR acBuf[_MAX_PATH]; + + if ( ulRC != NO_ERROR ) + { + debug( "DosGetInfoBlocks() failed, rc = %u", ulRC ); + return NULL; + } + + pcEnd = SDL_strrchr( pib->pib_pchcmd, '\\' ); + if ( pcEnd != NULL ) + pcEnd++; + else + { + if ( pib->pib_pchcmd[1] == ':' ) + pcEnd = &pib->pib_pchcmd[2]; + else + return NULL; + } + + cbResult = pcEnd - pib->pib_pchcmd; + SDL_memcpy( &acBuf, pib->pib_pchcmd, cbResult ); + acBuf[cbResult] = '\0'; + + return OS2_SysToUTF8( acBuf ); +} + +char * +SDL_GetPrefPath(const char *org, const char *app) +{ + PSZ pszPath = SDL_getenv( "HOME" ); + CHAR acBuf[_MAX_PATH]; + LONG lPosApp, lPosOrg; + PSZ pszApp, pszOrg = OS2_UTF8ToSys( org ); + + if ( pszOrg == NULL ) + { + SDL_OutOfMemory(); + return NULL; + } + + if ( pszPath == NULL ) + { + pszPath = SDL_getenv( "ETC" ); + if ( pszPath == NULL ) + return NULL; + } + + lPosApp = SDL_snprintf( &acBuf, sizeof(acBuf) - 1, "%s\\%s", pszPath, pszOrg ); + SDL_free( pszOrg ); + if ( lPosApp == -1 ) + return NULL; + + mkdir( &acBuf ); + + pszApp = OS2_UTF8ToSys( app ); + if ( pszApp == NULL ) + { + SDL_OutOfMemory(); + return NULL; + } + + lPosOrg = SDL_snprintf( &acBuf[lPosApp], sizeof(acBuf) - lPosApp - 1, "\\%s", + pszApp ); + SDL_free( pszApp ); + if ( lPosOrg == -1 ) + return NULL; + + mkdir( &acBuf ); + *((PUSHORT)&acBuf[lPosApp + lPosOrg]) = (USHORT)'\0\\'; + + return OS2_SysToUTF8( &acBuf ); +} + +#endif /* SDL_FILESYSTEM_OS2 */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/loadso/os2/SDL_sysloadso.c b/src/loadso/os2/SDL_sysloadso.c new file mode 100644 index 000000000..7d08f94b5 --- /dev/null +++ b/src/loadso/os2/SDL_sysloadso.c @@ -0,0 +1,79 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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" + +#ifdef SDL_LOADSO_OS2 + +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ +/* System dependent library loading routines */ + +#include "SDL_loadso.h" +#include ".\core\os2\SDL_os2.h" + +#define INCL_DOSMODULEMGR +#define INCL_DOSERRORS +#include + +void * +SDL_LoadObject(const char *sofile) +{ + ULONG ulRC; + HMODULE hModule; + PSZ pszModName = OS2_UTF8ToSys( sofile ); + CHAR acError[256]; + + ulRC = DosLoadModule( &acError, sizeof(acError), pszModName, &hModule ); + SDL_free( pszModName ); + if ( ulRC != NO_ERROR ) + { + SDL_SetError( "Failed loading, module: %s", pszModName ); + return NULL; + } + + return (void *)hModule; +} + +void * +SDL_LoadFunction(void *handle, const char *name) +{ + ULONG ulRC; + PFN pFN; + + ulRC = DosQueryProcAddr( (HMODULE)handle, 0, name, &pFN ); + if ( ulRC ) + { + SDL_SetError( "Failed loading, procedure: %s", name ); + return NULL; + } + + return (void *)pFN; +} + +void +SDL_UnloadObject(void *handle) +{ + if ( handle != NULL ) + DosFreeModule( (HMODULE)handle ); +} + +#endif /* SDL_LOADSO_OS2 */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/thread/os2/SDL_sysmutex.c b/src/thread/os2/SDL_sysmutex.c new file mode 100644 index 000000000..40d094d8d --- /dev/null +++ b/src/thread/os2/SDL_sysmutex.c @@ -0,0 +1,132 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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_THREAD_OS2 + +/* An implementation of mutexes for OS/2 */ + +#include "SDL_thread.h" +#include "SDL_systhread_c.h" +#include "../../core/os2/SDL_os2.h" + +#define INCL_DOSSEMAPHORES +#define INCL_DOSERRORS +#include + +struct SDL_mutex +{ + ULONG ulHandle; +}; + +/* Create a mutex */ +SDL_mutex * +SDL_CreateMutex(void) +{ + ULONG ulRC; + HMTX hMtx; + + ulRC = DosCreateMutexSem( NULL, &hMtx, 0, FALSE ); + if ( ulRC != NO_ERROR ) + { + debug( "DosCreateMutexSem(), rc = %u", ulRC ); + return NULL; + } + + return (SDL_mutex *)hMtx; +} + +/* Free the mutex */ +void +SDL_DestroyMutex(SDL_mutex * mutex) +{ + ULONG ulRC; + HMTX hMtx = (HMTX)mutex; + + ulRC = DosCloseMutexSem( hMtx ); + if ( ulRC != NO_ERROR ) + debug( "DosCloseMutexSem(), rc = %u", ulRC ); +} + +/* Lock the mutex */ +int +SDL_LockMutex(SDL_mutex * mutex) +{ + ULONG ulRC; + HMTX hMtx = (HMTX)mutex; + + if ( hMtx == NULLHANDLE ) + return SDL_SetError( "Passed a NULL mutex" ); + + ulRC = DosRequestMutexSem( hMtx, SEM_INDEFINITE_WAIT ); + if ( ulRC != NO_ERROR ) + { + debug( "DosRequestMutexSem(), rc = %u", ulRC ); + return -1; + } + + return 0; +} + +/* try Lock the mutex */ +int +SDL_TryLockMutex(SDL_mutex * mutex) +{ + ULONG ulRC; + HMTX hMtx = (HMTX)mutex; + + if ( hMtx == NULLHANDLE ) + return SDL_SetError( "Passed a NULL mutex" ); + + ulRC = DosRequestMutexSem( hMtx, SEM_IMMEDIATE_RETURN ); + + if ( ulRC == ERROR_TIMEOUT ) + return SDL_MUTEX_TIMEDOUT; + + if ( ulRC != NO_ERROR ) + { + debug( "DosRequestMutexSem(), rc = %u", ulRC ); + return -1; + } + + return 0; +} + +/* Unlock the mutex */ +int +SDL_UnlockMutex(SDL_mutex * mutex) +{ + ULONG ulRC; + HMTX hMtx = (HMTX)mutex; + + if ( hMtx == NULLHANDLE ) + return SDL_SetError( "Passed a NULL mutex" ); + + ulRC = DosReleaseMutexSem( hMtx ); + if ( ulRC != NO_ERROR ) + return SDL_SetError( "DosReleaseMutexSem(), rc = %u", ulRC ); + + return 0; +} + +#endif /* SDL_THREAD_OS2 */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/thread/os2/SDL_syssem.c b/src/thread/os2/SDL_syssem.c new file mode 100644 index 000000000..688b6c619 --- /dev/null +++ b/src/thread/os2/SDL_syssem.c @@ -0,0 +1,196 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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_THREAD_OS2 + +/* An implementation of semaphores for OS/2 */ + +#include "SDL_thread.h" +#include "../../core/os2/SDL_os2.h" + +#define INCL_DOSSEMAPHORES +#define INCL_DOSERRORS +#define INCL_DOSMISC +#include + +struct SDL_semaphore { + HEV hEv; + HMTX hMtx; + ULONG cPost; +}; + + +SDL_sem * +SDL_CreateSemaphore(Uint32 initial_value) +{ + ULONG ulRC; + SDL_sem *pSDLSem = SDL_malloc( sizeof(SDL_sem) ); + + if ( pSDLSem == NULL ) + { + SDL_OutOfMemory(); + return NULL; + } + + ulRC = DosCreateEventSem( NULL, &pSDLSem->hEv, DCE_AUTORESET, FALSE ); + if ( ulRC != NO_ERROR ) + { + debug( "DosCreateEventSem(), rc = %u", ulRC ); + SDL_free( pSDLSem ); + return NULL; + } + + ulRC = DosCreateMutexSem( NULL, &pSDLSem->hMtx, 0, FALSE ); + if ( ulRC != NO_ERROR ) + { + debug( "DosCreateMutexSem(), rc = %u", ulRC ); + DosCloseEventSem( pSDLSem->hEv ); + SDL_free( pSDLSem ); + return NULL; + } + + pSDLSem->cPost = initial_value; + + return pSDLSem; +} + +void +SDL_DestroySemaphore(SDL_sem * sem) +{ + if ( sem == NULL ) + return; + + DosCloseMutexSem( sem->hMtx ); + DosCloseEventSem( sem->hEv ); + SDL_free( sem ); +} + +int +SDL_SemWaitTimeout(SDL_sem * sem, Uint32 timeout) +{ + ULONG ulRC; + ULONG ulStartTime, ulCurTime; + ULONG ulTimeout; + ULONG cPost; + + if ( sem == NULL ) + return SDL_SetError( "Passed a NULL sem" ); + + if ( timeout != SEM_INDEFINITE_WAIT ) + DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &ulStartTime, sizeof(ULONG) ); + + while( TRUE ) + { + ulRC = DosRequestMutexSem( sem->hMtx, SEM_INDEFINITE_WAIT ); + if ( ulRC != NO_ERROR ) + return SDL_SetError( "DosRequestMutexSem() failed, rc = %u", ulRC ); + + cPost = sem->cPost; + if ( sem->cPost != 0 ) + sem->cPost--; + + DosReleaseMutexSem( sem->hMtx ); + + if ( cPost != 0 ) + break; + + if ( timeout == SEM_INDEFINITE_WAIT ) + ulTimeout = SEM_INDEFINITE_WAIT; + else + { + DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &ulCurTime, sizeof(ULONG) ); + ulTimeout = ulCurTime - ulStartTime; + if ( timeout < ulTimeout ) + return SDL_MUTEX_TIMEDOUT; + ulTimeout = timeout - ulTimeout; + } + + ulRC = DosWaitEventSem( sem->hEv, ulTimeout ); + if ( ulRC == ERROR_TIMEOUT ) + return SDL_MUTEX_TIMEDOUT; + + if ( ulRC != NO_ERROR ) + return SDL_SetError( "DosWaitEventSem() failed, rc = %u", ulRC ); + } + + return 0; +} + +int +SDL_SemTryWait(SDL_sem * sem) +{ + return SDL_SemWaitTimeout( sem, 0 ); +} + +int +SDL_SemWait(SDL_sem * sem) +{ + return SDL_SemWaitTimeout( sem, SDL_MUTEX_MAXWAIT ); +} + +Uint32 +SDL_SemValue(SDL_sem * sem) +{ + ULONG ulRC; + + if ( sem == NULL ) + { + SDL_SetError( "Passed a NULL sem" ); + return 0; + } + + ulRC = DosRequestMutexSem( sem->hMtx, SEM_INDEFINITE_WAIT ); + if ( ulRC != NO_ERROR ) + return SDL_SetError( "DosRequestMutexSem() failed, rc = %u", ulRC ); + + ulRC = sem->cPost; + DosReleaseMutexSem( sem->hMtx ); + + return ulRC; +} + +int +SDL_SemPost(SDL_sem * sem) +{ + ULONG ulRC; + + if ( sem == NULL ) + return SDL_SetError( "Passed a NULL sem" ); + + ulRC = DosRequestMutexSem( sem->hMtx, SEM_INDEFINITE_WAIT ); + if ( ulRC != NO_ERROR ) + return SDL_SetError( "DosRequestMutexSem() failed, rc = %u", ulRC ); + + sem->cPost++; + + ulRC = DosPostEventSem( sem->hEv ); + if ( ( ulRC != NO_ERROR ) && ( ulRC != ERROR_ALREADY_POSTED ) ) + debug( "DosPostEventSem() failed, rc = %u", ulRC ); + + DosReleaseMutexSem( sem->hMtx ); + + return 0; +} + +#endif /* SDL_THREAD_OS2 */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/thread/os2/SDL_systhread.c b/src/thread/os2/SDL_systhread.c new file mode 100644 index 000000000..15453f7da --- /dev/null +++ b/src/thread/os2/SDL_systhread.c @@ -0,0 +1,187 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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_THREAD_OS2 + +/* Thread management routines for SDL */ + +#include "SDL_thread.h" +#include "../SDL_systhread.h" +#include "../SDL_thread_c.h" +#include "../SDL_systhread.h" +#include "SDL_systls_c.h" +#include "../../core/os2/SDL_os2.h" + +#define INCL_DOSPROCESS +#define INCL_DOSERRORS +#include + +#ifndef SDL_PASSED_BEGINTHREAD_ENDTHREAD +/* We'll use the C library from this DLL */ +#include + +/* Cygwin gcc-3 ... MingW64 (even with a i386 host) does this like MSVC. */ +#if (defined(__MINGW32__) && (__GNUC__ < 4)) +typedef unsigned long (__cdecl *pfnSDL_CurrentBeginThread) (void *, unsigned, + unsigned (__stdcall *func)(void *), void *arg, + unsigned, unsigned *threadID); +typedef void (__cdecl *pfnSDL_CurrentEndThread)(unsigned code); + +#elif defined(__WATCOMC__) +/* This is for Watcom targets except OS2 */ +#if __WATCOMC__ < 1240 +#define __watcall +#endif +typedef unsigned long (__watcall * pfnSDL_CurrentBeginThread) (void *, + unsigned, + unsigned + (__stdcall * + func) (void + *), + void *arg, + unsigned, + unsigned + *threadID); +typedef void (__watcall * pfnSDL_CurrentEndThread) (unsigned code); + +#else +typedef uintptr_t(__cdecl * pfnSDL_CurrentBeginThread) (void *, unsigned, + unsigned (__stdcall * + func) (void + *), + void *arg, unsigned, + unsigned *threadID); +typedef void (__cdecl * pfnSDL_CurrentEndThread) (unsigned code); +#endif +#endif /* !SDL_PASSED_BEGINTHREAD_ENDTHREAD */ + + +typedef struct ThreadStartParms { + void *args; + pfnSDL_CurrentEndThread pfnCurrentEndThread; +} tThreadStartParms, *pThreadStartParms; + +static void RunThread(void *data) +{ + pThreadStartParms pThreadParms = (pThreadStartParms) data; + pfnSDL_CurrentEndThread pfnEndThread = pThreadParms->pfnCurrentEndThread; + void *args = pThreadParms->args; + + SDL_free( pThreadParms ); + + if ( ppSDLTLSData != NULL ) + *ppSDLTLSData = NULL; + + SDL_RunThread( args ); + + if ( pfnEndThread != NULL ) + pfnEndThread(); +} + + + +#ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD +int +SDL_SYS_CreateThread(SDL_Thread * thread, void *args, + pfnSDL_CurrentBeginThread pfnBeginThread, + pfnSDL_CurrentEndThread pfnEndThread) +#else +int +SDL_SYS_CreateThread(SDL_Thread * thread, void *args) +#endif /* SDL_PASSED_BEGINTHREAD_ENDTHREAD */ +{ + pThreadStartParms pThreadParms = SDL_malloc( sizeof(tThreadStartParms) ); + + if ( pThreadParms == NULL ) + return SDL_OutOfMemory(); + + // Save the function which we will have to call to clear the RTL of calling app! + pThreadParms->pfnCurrentEndThread = pfnEndThread; + // Also save the real parameters we have to pass to thread function + pThreadParms->args = args; + + // Start the thread using the runtime library of calling app! + thread->handle = (SYS_ThreadHandle) + #ifdef SDL_PASSED_BEGINTHREAD_ENDTHREAD + ( (size_t) pfnBeginThread( RunThread, NULL, 65535, pThreadParms ) ); + #else + _beginthread( RunThread, NULL, 65535, pThreadParms ); + #endif + + if ( thread->handle == -1 ) + return SDL_SetError( "Not enough resources to create thread" ); + + return 0; +} + +void +SDL_SYS_SetupThread(const char *name) +{ + return; +} + +SDL_threadID +SDL_ThreadID(void) +{ + PTIB tib; + PPIB pib; + + DosGetInfoBlocks( &tib, &pib ); + return tib->tib_ptib2->tib2_ultid; +} + +int +SDL_SYS_SetThreadPriority(SDL_ThreadPriority priority) +{ + ULONG ulRC; + + ulRC = DosSetPriority( PRTYS_THREAD, + priority == SDL_THREAD_PRIORITY_LOW + ? PRTYC_IDLETIME + : priority == SDL_THREAD_PRIORITY_HIGH + ? PRTYC_TIMECRITICAL + : PRTYC_REGULAR , + 0, 0 ); + if ( ulRC != NO_ERROR ) + return SDL_SetError( "DosSetPriority() failed, rc = %u", ulRC ); + + return 0; +} + +void +SDL_SYS_WaitThread(SDL_Thread * thread) +{ + ULONG ulRC = DosWaitThread( (PTID)&thread->handle, DCWW_WAIT ); + + if ( ulRC != NO_ERROR ) + debug( "DosWaitThread() failed, rc = %u", ulRC ); +} + +void +SDL_SYS_DetachThread(SDL_Thread * thread) +{ + return; +} + +#endif /* SDL_THREAD_OS2 */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/thread/os2/SDL_systhread_c.h b/src/thread/os2/SDL_systhread_c.h new file mode 100644 index 000000000..ba16277d0 --- /dev/null +++ b/src/thread/os2/SDL_systhread_c.h @@ -0,0 +1,25 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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" + +typedef int SYS_ThreadHandle; + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/thread/os2/SDL_systls.c b/src/thread/os2/SDL_systls.c new file mode 100644 index 000000000..023a2417f --- /dev/null +++ b/src/thread/os2/SDL_systls.c @@ -0,0 +1,89 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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_THREAD_OS2 + +#include "../../core/os2/SDL_os2.h" + +#include "SDL_thread.h" +#include "../SDL_thread_c.h" + +#define INCL_DOSPROCESS +#define INCL_DOSERRORS +#include + +SDL_TLSData **ppSDLTLSData = NULL; + +static ULONG cTLSAlloc = 0; + +// SDL_OS2TLSAlloc() called from SDL_InitSubSystem() +void SDL_OS2TLSAlloc() +{ + ULONG ulRC; + + if ( ( cTLSAlloc == 0 ) || ( ppSDLTLSData == NULL ) ) + { + // First call - allocate the thread local memory (1 DWORD). + ulRC = DosAllocThreadLocalMemory( 1, (PULONG *)&ppSDLTLSData ); + if ( ulRC != NO_ERROR ) + debug( "DosAllocThreadLocalMemory() failed, rc = %u", ulRC ); + } + cTLSAlloc++; +} + +// SDL_OS2TLSFree() called from SDL_QuitSubSystem() +void SDL_OS2TLSFree() +{ + ULONG ulRC; + + if ( cTLSAlloc != 0 ) + cTLSAlloc--; + + if ( ( cTLSAlloc == 0 ) && ( ppSDLTLSData != NULL ) ) + { + // Last call - free the thread local memory. + ulRC = DosFreeThreadLocalMemory( (PULONG)ppSDLTLSData ); + if ( ulRC != NO_ERROR ) + debug( "DosFreeThreadLocalMemory() failed, rc = %u", ulRC ); + else + ppSDLTLSData = NULL; + } +} + +SDL_TLSData *SDL_SYS_GetTLSData() +{ + return ppSDLTLSData == NULL ? NULL : *ppSDLTLSData; +} + +int SDL_SYS_SetTLSData(SDL_TLSData *data) +{ + if ( ppSDLTLSData == NULL ) + return -1; + + *ppSDLTLSData = data; + return 0; +} + +#endif /* SDL_THREAD_OS2 */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/thread/os2/SDL_systls_c.h b/src/thread/os2/SDL_systls_c.h new file mode 100644 index 000000000..7c63e9007 --- /dev/null +++ b/src/thread/os2/SDL_systls_c.h @@ -0,0 +1,38 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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_THREAD_OS2 + +#include "../SDL_thread_c.h" + +extern SDL_TLSData **ppSDLTLSData; + +// SDL_OS2TLSAlloc() called from SDL_InitSubSystem() +void SDL_OS2TLSAlloc(); + +// SDL_OS2TLSFree() called from SDL_QuitSubSystem() +void SDL_OS2TLSFree(); + +#endif /* SDL_THREAD_OS2 */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/timer/os2/SDL_systimer.c b/src/timer/os2/SDL_systimer.c new file mode 100644 index 000000000..aa4ac9302 --- /dev/null +++ b/src/timer/os2/SDL_systimer.c @@ -0,0 +1,189 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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_TIMER_OS2 + +#include "SDL_timer.h" +#include "../../core/os2/SDL_os2.h" + +#define INCL_DOSERRORS +#define INCL_DOSMISC +#define INCL_DOSPROFILE +#define INCL_DOSSEMAPHORES +#define INCL_DOSDATETIME +#define INCL_DOSPROCESS +#define INCL_DOSEXCEPTIONS +#include + +// No need to switch priorities in SDL_Delay() for OS/2 versions > Warp3 fp 42. +//#define _SWITCH_PRIORITY + +typedef unsigned long long ULLONG; + +static ULONG ulTmrFreq = 0; +static ULLONG ullTmrStart; + +void +SDL_TicksInit(void) +{ + ULONG ulRC; + + ulRC = DosTmrQueryFreq( &ulTmrFreq ); + if ( ulRC != NO_ERROR ) + { + debug( "DosTmrQueryFreq() failed, rc = %u", ulRC ); + } + else + { + ulRC = DosTmrQueryTime( (PQWORD)&ullTmrStart ); + if ( ulRC == NO_ERROR ) + return; + + debug( "DosTmrQueryTime() failed, rc = %u", ulRC ); + } + + ulTmrFreq = 0; // Error - use DosQuerySysInfo() for timer. + + DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, (PULONG)&ullTmrStart, + sizeof(ULONG) ); +} + +void +SDL_TicksQuit(void) +{ +} + +Uint32 +SDL_GetTicks(void) +{ + ULONG ulResult; + ULLONG ullTmrNow; + + if ( ulTmrFreq == 0 ) + // Was not initialized. + SDL_TicksInit(); + + if ( ulTmrFreq != 0 ) + { + DosTmrQueryTime( (PQWORD)&ullTmrNow ); + ulResult = ( ullTmrNow - ullTmrStart ) * 1000 / ulTmrFreq; + } + else + { + DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, (PULONG)&ullTmrNow, + sizeof(ULONG) ); + ulResult = (ULONG)ullTmrNow - (ULONG)ullTmrStart; + } + + return ulResult; +} + +Uint64 +SDL_GetPerformanceCounter(void) +{ + QWORD qwTmrNow; + + if ( ( ulTmrFreq == 0 ) || ( DosTmrQueryTime( &qwTmrNow ) != NO_ERROR ) ) + return SDL_GetTicks(); + + return *((Uint64 *)&qwTmrNow); +} + +Uint64 +SDL_GetPerformanceFrequency(void) +{ + return ulTmrFreq == 0 ? 1000 : (Uint64)ulTmrFreq; +} + +void +SDL_Delay(Uint32 ms) +{ + HTIMER hTimer = NULLHANDLE; + ULONG ulRC; +#ifdef _SWITCH_PRIORITY + PPIB pib; + PTIB tib; + BOOL fSetPriority = ms < 50; + ULONG ulSavePriority; + ULONG ulNesting; +#endif + HEV hevTimer; + + if ( ms == 0 ) + { + DosSleep( 0 ); + return; + } + + ulRC = DosCreateEventSem( NULL, &hevTimer, DC_SEM_SHARED, FALSE ); + if ( ulRC != NO_ERROR ) + { + debug( "DosAsyncTimer() failed, rc = %u", ulRC ); + DosSleep( ms ); + return; + } + +#ifdef _SWITCH_PRIORITY + if ( fSetPriority ) + { + if ( DosGetInfoBlocks( &tib, &pib ) != NO_ERROR ) + fSetPriority = FALSE; + else + { + ulSavePriority = tib->tib_ptib2->tib2_ulpri; + if ( ( (ulSavePriority & 0xFF00) == 0x0300 ) || // already have high pr. + ( DosEnterMustComplete( &ulNesting ) != NO_ERROR ) ) + fSetPriority = FALSE; + else + DosSetPriority( PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0 ); + } + } +#endif + + DosResetEventSem( hevTimer, &ulRC ); + ulRC = DosAsyncTimer( ms, (HSEM)hevTimer, &hTimer ); + +#ifdef _SWITCH_PRIORITY + if ( fSetPriority ) + { + if ( DosSetPriority( PRTYS_THREAD, (ulSavePriority >> 8) & 0xFF, 0, 0 ) == + NO_ERROR ) + DosSetPriority( PRTYS_THREAD, 0, ulSavePriority & 0xFF, 0 ); + + DosExitMustComplete( &ulNesting ); + } +#endif + + if ( ulRC != NO_ERROR ) + debug( "DosAsyncTimer() failed, rc = %u", ulRC ); + else + DosWaitEventSem( hevTimer, SEM_INDEFINITE_WAIT ); + + if ( ulRC != NO_ERROR ) + DosSleep( ms ); + + DosCloseEventSem( hevTimer ); +} + +#endif /* SDL_TIMER_OS2 */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/os2/SDL_os2dive.c b/src/video/os2/SDL_os2dive.c new file mode 100644 index 000000000..d4f49828f --- /dev/null +++ b/src/video/os2/SDL_os2dive.c @@ -0,0 +1,348 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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" +#include "../SDL_sysvideo.h" +#define INCL_WIN +#define INCL_GPI +#include +#define _MEERROR_H_ +#include +#include +#define INCL_MM_OS2 +#include +#include +#include "SDL_os2output.h" + +typedef struct _VODATA { + HDIVE hDive; + PVOID pBuffer; + ULONG ulDIVEBufNum; + FOURCC fccColorEncoding; + ULONG ulWidth; + ULONG ulHeight; + BOOL fBlitterReady; +} VODATA; + +static BOOL voQueryInfo(PVIDEOOUTPUTINFO pInfo); +static PVODATA voOpen(); +static VOID voClose(PVODATA pVOData); +static BOOL voSetVisibleRegion(PVODATA pVOData, HWND hwnd, + SDL_DisplayMode *pSDLDisplayMode, + HRGN hrgnShape, BOOL fVisible); +static PVOID voVideoBufAlloc(PVODATA pVOData, ULONG ulWidth, ULONG ulHeight, + ULONG ulBPP, ULONG fccColorEncoding, + PULONG pulScanLineSize); +static VOID voVideoBufFree(PVODATA pVOData); +static BOOL voUpdate(PVODATA pVOData, HWND hwnd, SDL_Rect *pSDLRects, + ULONG cSDLRects); + +OS2VIDEOOUTPUT voDive = { + voQueryInfo, + voOpen, + voClose, + voSetVisibleRegion, + voVideoBufAlloc, + voVideoBufFree, + voUpdate +}; + + +static BOOL voQueryInfo(PVIDEOOUTPUTINFO pInfo) +{ + DIVE_CAPS sDiveCaps = { 0 }; + FOURCC fccFormats[100] = { 0 }; + + // Query information about display hardware from DIVE. + + sDiveCaps.pFormatData = &fccFormats; + sDiveCaps.ulFormatLength = 100; + sDiveCaps.ulStructLen = sizeof(DIVE_CAPS); + + if ( DiveQueryCaps( &sDiveCaps, DIVE_BUFFER_SCREEN ) ) + { + debug( "DiveQueryCaps() failed." ); + return FALSE; + } + + if ( sDiveCaps.ulDepth < 8 ) + { + debug( "Not enough screen colors to run DIVE. " + "Must be at least 256 colors." ); + return FALSE; + } + + pInfo->ulBPP = sDiveCaps.ulDepth; + pInfo->fccColorEncoding = sDiveCaps.fccColorEncoding; + pInfo->ulScanLineSize = sDiveCaps.ulScanLineBytes; + pInfo->ulHorizResolution = sDiveCaps.ulHorizontalResolution; + pInfo->ulVertResolution = sDiveCaps.ulVerticalResolution; + + return TRUE; +} + +PVODATA voOpen() +{ + PVODATA pVOData = SDL_calloc( 1, sizeof(VODATA) ); + + if ( pVOData == NULL ) + { + SDL_OutOfMemory(); + return NULL; + } + + if ( DiveOpen( &pVOData->hDive, FALSE, NULL ) != DIVE_SUCCESS ) + { + SDL_free( pVOData ); + SDL_SetError( "DIVE: A display engine instance open failed" ); + return NULL; + } + + return pVOData; +} + +static VOID voClose(PVODATA pVOData) +{ + voVideoBufFree( pVOData ); + DiveClose( pVOData->hDive ); + SDL_free( pVOData ); +} + +static BOOL voSetVisibleRegion(PVODATA pVOData, HWND hwnd, + SDL_DisplayMode *pSDLDisplayMode, + HRGN hrgnShape, BOOL fVisible) +{ + HPS hps; + HRGN hrgn; + RGNRECT rgnCtl; + PRECTL prectl = NULL; + ULONG ulRC; + + if ( !fVisible ) + { + if ( pVOData->fBlitterReady ) + { + pVOData->fBlitterReady = FALSE; + DiveSetupBlitter( pVOData->hDive, 0 ); + debug( "DIVE blitter is tuned off" ); + } + return TRUE; + } + + // Query visible rectangles + + hps = WinGetPS( hwnd ); + hrgn = GpiCreateRegion( hps, 0, NULL ); + if ( hrgn == NULLHANDLE ) + { + WinReleasePS( hps ); + SDL_SetError( "GpiCreateRegion() failed" ); + } + else + { + WinQueryVisibleRegion( hwnd, hrgn ); + if ( hrgnShape != NULLHANDLE ) + GpiCombineRegion( hps, hrgn, hrgn, hrgnShape, CRGN_AND ); + + rgnCtl.ircStart = 1; + rgnCtl.crc = 0; + rgnCtl.ulDirection = 1; + GpiQueryRegionRects( hps, hrgn, NULL, &rgnCtl, NULL ); + if ( rgnCtl.crcReturned != 0 ) + { + prectl = SDL_malloc( rgnCtl.crcReturned * sizeof(RECTL) ); + if ( prectl != NULL ) + { + rgnCtl.ircStart = 1; + rgnCtl.crc = rgnCtl.crcReturned; + rgnCtl.ulDirection = 1; + GpiQueryRegionRects( hps, hrgn, NULL, &rgnCtl, prectl ); + } + else + SDL_OutOfMemory(); + } + GpiDestroyRegion( hps, hrgn ); + WinReleasePS( hps ); + + if ( prectl != NULL ) + { + // Setup DIVE blitter. + SETUP_BLITTER sSetupBlitter; + SWP swp; + POINTL pointl = { 0 }; + + WinQueryWindowPos( hwnd, &swp ); + WinMapWindowPoints( hwnd, HWND_DESKTOP, &pointl, 1 ); + + sSetupBlitter.ulStructLen = sizeof(SETUP_BLITTER); + sSetupBlitter.fccSrcColorFormat = pVOData->fccColorEncoding; + sSetupBlitter.fInvert = FALSE; + sSetupBlitter.ulSrcWidth = pVOData->ulWidth; + sSetupBlitter.ulSrcHeight = pVOData->ulHeight; + sSetupBlitter.ulSrcPosX = 0; + sSetupBlitter.ulSrcPosY = 0; + sSetupBlitter.ulDitherType = 0; + sSetupBlitter.fccDstColorFormat = FOURCC_SCRN; + sSetupBlitter.ulDstWidth = swp.cx; + sSetupBlitter.ulDstHeight = swp.cy; + sSetupBlitter.lDstPosX = 0; + sSetupBlitter.lDstPosY = 0; + sSetupBlitter.lScreenPosX = pointl.x; + sSetupBlitter.lScreenPosY = pointl.y; + + sSetupBlitter.ulNumDstRects = rgnCtl.crcReturned; + sSetupBlitter.pVisDstRects = prectl; + + ulRC = DiveSetupBlitter( pVOData->hDive, &sSetupBlitter ); + SDL_free( prectl ); + + if ( ulRC == DIVE_SUCCESS ) + { + pVOData->fBlitterReady = TRUE; + WinInvalidateRect( hwnd, NULL, TRUE ); + debug( "DIVE blitter is ready now." ); + return TRUE; + } + + SDL_SetError( "DiveSetupBlitter(), rc = 0x%X", ulRC ); + } // if ( prectl != NULL ) + } // if ( hrgn == NULLHANDLE ) else + + pVOData->fBlitterReady = FALSE; + DiveSetupBlitter( pVOData->hDive, 0 ); + return FALSE; +} + +static PVOID voVideoBufAlloc(PVODATA pVOData, ULONG ulWidth, ULONG ulHeight, + ULONG ulBPP, FOURCC fccColorEncoding, + PULONG pulScanLineSize) +{ + ULONG ulRC; + ULONG ulScanLineSize = ulWidth * (ulBPP >> 3); + + // Destroy previous buffer. + voVideoBufFree( pVOData ); + + if ( ( ulWidth == 0 ) || ( ulHeight == 0 ) || ( ulBPP == 0 ) ) + return NULL; + + // Bytes per line. + ulScanLineSize = ( ulScanLineSize + 3 ) & ~3; /* 4-byte aligning */ + *pulScanLineSize = ulScanLineSize; + + ulRC = DosAllocMem( &pVOData->pBuffer, + (ulHeight * ulScanLineSize) + sizeof(ULONG), + PAG_COMMIT | PAG_EXECUTE | PAG_READ | PAG_WRITE ); + if ( ulRC != NO_ERROR ) + { + debug( "DosAllocMem(), rc = %u", ulRC ); + return NULL; + } + + ulRC = DiveAllocImageBuffer( pVOData->hDive, &pVOData->ulDIVEBufNum, + fccColorEncoding, ulWidth, ulHeight, + ulScanLineSize, pVOData->pBuffer ); + if ( ulRC != DIVE_SUCCESS ) + { + debug( "DiveAllocImageBuffer(), rc = 0x%X", ulRC ); + DosFreeMem( pVOData->pBuffer ); + pVOData->pBuffer = NULL; + pVOData->ulDIVEBufNum = 0; + return NULL; + } + + pVOData->fccColorEncoding = fccColorEncoding; + pVOData->ulWidth = ulWidth; + pVOData->ulHeight = ulHeight; + + debug( "buffer: 0x%P, DIVE buffer number: %u", + pVOData->pBuffer, pVOData->ulDIVEBufNum ); + + return pVOData->pBuffer; +} + +static VOID voVideoBufFree(PVODATA pVOData) +{ + ULONG ulRC; + + if ( pVOData->ulDIVEBufNum != 0 ) + { + ulRC = DiveFreeImageBuffer( pVOData->hDive, pVOData->ulDIVEBufNum ); + if ( ulRC != DIVE_SUCCESS ) + debug( "DiveFreeImageBuffer(,%u), rc = %u", pVOData->ulDIVEBufNum, ulRC ); + else + debug( "DIVE buffer %u destroyed", pVOData->ulDIVEBufNum ); + + pVOData->ulDIVEBufNum = 0; + } + + if ( pVOData->pBuffer != NULL ) + { + ulRC = DosFreeMem( pVOData->pBuffer ); + if ( ulRC != NO_ERROR ) + debug( "DosFreeMem(), rc = %u", ulRC ); + + pVOData->pBuffer = NULL; + } +} + +static BOOL voUpdate(PVODATA pVOData, HWND hwnd, SDL_Rect *pSDLRects, + ULONG cSDLRects) +{ + ULONG ulRC; + + if ( !pVOData->fBlitterReady || ( pVOData->ulDIVEBufNum == 0 ) ) + { + debug( "DIVE blitter is not ready" ); + return FALSE; + } + + if ( pSDLRects != 0 ) + { + PBYTE pbLineMask; + + pbLineMask = SDL_stack_alloc( BYTE, pVOData->ulHeight ); + if ( pbLineMask == NULL ) + { + debug( "Not enough stack size" ); + return FALSE; + } + memset( pbLineMask, 0, pVOData->ulHeight ); + + for( ; ((LONG)cSDLRects) > 0; cSDLRects--, pSDLRects++ ) + memset( &pbLineMask[pSDLRects->y], 1, pSDLRects->h ); + + ulRC = DiveBlitImageLines( pVOData->hDive, pVOData->ulDIVEBufNum, + DIVE_BUFFER_SCREEN, pbLineMask ); + SDL_stack_free( pbLineMask ); + + if ( ulRC != DIVE_SUCCESS ) + debug( "DiveBlitImageLines(), rc = 0x%X", ulRC ); + } + else + { + ulRC = DiveBlitImage( pVOData->hDive, pVOData->ulDIVEBufNum, + DIVE_BUFFER_SCREEN ); + if ( ulRC != DIVE_SUCCESS ) + debug( "DiveBlitImage(), rc = 0x%X", ulRC ); + } + + return ulRC == DIVE_SUCCESS; +} diff --git a/src/video/os2/SDL_os2messagebox.c b/src/video/os2/SDL_os2messagebox.c new file mode 100644 index 000000000..936119932 --- /dev/null +++ b/src/video/os2/SDL_os2messagebox.c @@ -0,0 +1,593 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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 + +/* Display a OS/2 message box */ + +#include "SDL.h" +#include "../../core/os2/SDL_os2.h" +#include "SDL_os2video.h" +#define INCL_WIN +#include + +#define IDD_TEXT_MESSAGE 1001 +#define IDD_BITMAP 1002 +#define IDD_PB_FIRST 1003 + +typedef struct _MSGBOXDLGDATA { + USHORT cb; + HWND hwndUnder; +} MSGBOXDLGDATA, *PMSGBOXDLGDATA; + +static VOID _wmInitDlg(HWND hwnd, PMSGBOXDLGDATA pDlgData) +{ + HPS hps = WinGetPS( hwnd ); + POINTL aptText[TXTBOX_COUNT]; + HENUM hEnum; + HWND hWndNext; + CHAR acBuf[256]; + ULONG cbBuf; + ULONG cButtons = 0; + ULONG ulButtonsCY = 0; + ULONG ulButtonsCX = 0; + RECTL rectl; + ULONG ulX; + ULONG ulIdx; + struct _BUTTON { + HWND hwnd; // Button window handle. + ULONG ulCX; // Button width in dialog coordinates. + } aButtons[32]; + RECTL rectlItem; + HAB hab = WinQueryAnchorBlock( hwnd ); + + /* --- Align the buttons to the right/bottom. --- */ + + // Collect window handles of all buttons in dialog. + + hEnum = WinBeginEnumWindows( hwnd ); + + while( ( hWndNext = WinGetNextWindow( hEnum ) ) != NULLHANDLE ) + { + if ( WinQueryClassName( hWndNext, sizeof(acBuf), &acBuf ) == 0 ) + continue; + + if ( strcmp( &acBuf, "#3" ) == 0 ) // Class name of button. + { + if ( cButtons < sizeof(aButtons) / sizeof(struct _BUTTON) ) + { + aButtons[cButtons].hwnd = hWndNext; + cButtons++; + } + } + } + WinEndEnumWindows( hEnum ); + + // Query size of text for each button, get width of each button, total + // buttons width (ulButtonsCX) and max. height (ulButtonsCX) in _dialog + // coordinates_. + + hps = WinGetPS( hwnd ); + + for( ulIdx = 0; ulIdx < cButtons; ulIdx++ ) + { + // Query size of text in window coordinates. + cbBuf = WinQueryWindowText( aButtons[ulIdx].hwnd, sizeof(acBuf), &acBuf ); + GpiQueryTextBox( hps, cbBuf, acBuf, TXTBOX_COUNT, &aptText ); + aptText[TXTBOX_TOPRIGHT].x -= aptText[TXTBOX_BOTTOMLEFT].x; + aptText[TXTBOX_TOPRIGHT].y -= aptText[TXTBOX_BOTTOMLEFT].y; + // Convert text size to dialog coordinates. + WinMapDlgPoints( hwnd, &aptText[TXTBOX_TOPRIGHT], 1, FALSE ); + // Add vertical and horizontal space for button's frame (dialog coord.). + if ( aptText[TXTBOX_TOPRIGHT].x < 30 ) // Minimal button width. + aptText[TXTBOX_TOPRIGHT].x = 30; + else + aptText[TXTBOX_TOPRIGHT].x += 4; + aptText[TXTBOX_TOPRIGHT].y += 3; + + aButtons[ulIdx].ulCX = aptText[TXTBOX_TOPRIGHT].x; // Store button width. + ulButtonsCX += aptText[TXTBOX_TOPRIGHT].x + 2; // Add total btn. width. + // Get max. height for buttons. + if ( ulButtonsCY < aptText[TXTBOX_TOPRIGHT].y ) + ulButtonsCY = aptText[TXTBOX_TOPRIGHT].y + 1; + } + + WinReleasePS( hps ); + + // Expand horizontal size of the window to fit all buttons and move window + // to the center of parent window. + + // Convert total width of buttons to window coordinates. + aptText[0].x = ulButtonsCX + 4; + WinMapDlgPoints( hwnd, &aptText[0], 1, TRUE ); + // Check width of the window and expand as needed. + WinQueryWindowRect( hwnd, &rectlItem ); + if ( rectlItem.xRight <= aptText[0].x ) + rectlItem.xRight = aptText[0].x; + + // Move window rectangle to the center of owner window. + WinQueryWindowRect( pDlgData->hwndUnder, &rectl ); + // Left-bottom point of centered dialog on owner window. + rectl.xLeft = ( rectl.xRight - rectlItem.xRight ) / 2; + rectl.yBottom = ( rectl.yTop - rectlItem.yTop ) / 2; + // Map left-bottom point to desktop. + WinMapWindowPoints( pDlgData->hwndUnder, HWND_DESKTOP, (PPOINTL)&rectl, 1 ); + WinOffsetRect( hab, &rectlItem, rectl.xLeft, rectl.yBottom ); + + // Set new rectangle for the window. + WinSetWindowPos( hwnd, HWND_TOP, rectlItem.xLeft, rectlItem.yBottom, + rectlItem.xRight - rectlItem.xLeft, + rectlItem.yTop - rectlItem.yBottom, + SWP_SIZE | SWP_MOVE ); + + // Set buttons positions. + + // Get horizontal position for the first button. + WinMapDlgPoints( hwnd, (PPOINTL)&rectlItem, 2, FALSE ); // Win size to dlg coord. + ulX = rectlItem.xRight - rectlItem.xLeft - ulButtonsCX - 2; // First button position. + + // Set positions and sizes for all buttons. + for( ulIdx = 0; ulIdx < cButtons; ulIdx++ ) + { + // Get poisition and size for the button in dialog coordinates. + aptText[0].x = ulX; + aptText[0].y = 2; + aptText[1].x = aButtons[ulIdx].ulCX; + aptText[1].y = ulButtonsCY; + // Convert to window coordinates. + WinMapDlgPoints( hwnd, &aptText, 2, TRUE ); + + WinSetWindowPos( aButtons[ulIdx].hwnd, HWND_TOP, + aptText[0].x, aptText[0].y, aptText[1].x, aptText[1].y, + SWP_MOVE | SWP_SIZE ); + + // Offset horizontal position for the next button. + ulX += aButtons[ulIdx].ulCX + 2; + } + + // Set right bound of the text to right bound of the last button and + // bottom bound of the text just above the buttons. + + aptText[2].x = 25; // Left bound of text in dlg coordinates. + aptText[2].y = ulButtonsCY + 3; // Bottom bound of the text in dlg coords. + WinMapDlgPoints( hwnd, &aptText[2], 1, TRUE ); // Convert ^^^ to win. coords. + hWndNext = WinWindowFromID( hwnd, IDD_TEXT_MESSAGE ); + WinQueryWindowRect( hWndNext, &rectlItem ); + rectlItem.xLeft = aptText[2].x; + rectlItem.yBottom = aptText[2].y; + // Right bound of the text equals right bound of the last button. + rectlItem.xRight = aptText[0].x + aptText[1].x; + WinSetWindowPos( hWndNext, HWND_TOP, rectlItem.xLeft, rectlItem.yBottom, + rectlItem.xRight - rectlItem.xLeft, + rectlItem.yTop - rectlItem.yBottom, + SWP_MOVE | SWP_SIZE ); +} + +MRESULT EXPENTRY DynDlgProc(HWND hwnd, USHORT message, MPARAM mp1, MPARAM mp2) +{ + switch( message ) + { + case WM_INITDLG: + _wmInitDlg( hwnd, (PMSGBOXDLGDATA)mp2 ); + break; + + case WM_COMMAND: + switch( SHORT1FROMMP(mp1) ) + { + case DID_OK: + WinDismissDlg( hwnd, FALSE ); + break; + + default: + break; + } + + default: + return( WinDefDlgProc( hwnd, message, mp1, mp2 ) ); + } + + return FALSE; +} + +static HWND _makeDlg(const SDL_MessageBoxData *messageboxdata) +{ + SDL_MessageBoxButtonData *pSDLBtnData = + (SDL_MessageBoxButtonData *)messageboxdata->buttons; + ULONG cSDLBtnData = messageboxdata->numbuttons; + + PSZ pszTitle = OS2_UTF8ToSys( (PSZ)messageboxdata->title ); + ULONG cbTitle = pszTitle == NULL ? + 0 : strlen( pszTitle ); + PSZ pszText = OS2_UTF8ToSys( (PSZ)messageboxdata->message ); + ULONG cbText = pszText == NULL ? + 0 : strlen( pszText ); + + PDLGTEMPLATE pTemplate; + ULONG cbTemplate; + ULONG ulIdx; + PCHAR pcDlgData; + PDLGTITEM pDlgItem; + PSZ pszBtnText; + ULONG cbBtnText; + HWND hwnd; + SDL_MessageBoxColor *pSDLColors = messageboxdata->colorScheme == NULL + ? NULL + : (SDL_MessageBoxColor *)&messageboxdata->colorScheme->colors; + SDL_MessageBoxColor *pSDLColor; + MSGBOXDLGDATA stDlgData; + + /* Build a dialog tamplate in memory */ + + // Size of template (cbTemplate). + + cbTemplate = sizeof(DLGTEMPLATE) + ( (2 + cSDLBtnData) * sizeof(DLGTITEM) ) + + sizeof(ULONG) + // First item data - frame control data. + cbTitle + 1 + // First item data - frame title + ZERO. + cbText + 1 + // Second item data - ststic text + ZERO. + 3; // Third item data - system icon Id. + // Button items datas - text for buttons. + for( ulIdx = 0; ulIdx < cSDLBtnData; ulIdx++ ) + { + pszBtnText = (PSZ)pSDLBtnData[ulIdx].text; + cbTemplate += pszBtnText == NULL ? 1 : ( strlen( pszBtnText ) + 1 ); + } + // Presentation parameter space. + if ( pSDLColors != NULL ) + cbTemplate += 26 /* PP for frame. */ + 26 /* PP for static text. */ + + ( 48 * cSDLBtnData ); /* PP for buttons. */ + + // Allocate memory for the dialog template. + pTemplate = SDL_malloc( cbTemplate ); + // Pointer on data for dialog items in allocated memory. + pcDlgData = &((PCHAR)pTemplate)[ sizeof(DLGTEMPLATE) + + ( (2 + cSDLBtnData) * sizeof(DLGTITEM) ) ]; + + /* Header info */ + + pTemplate->cbTemplate = cbTemplate; /* size of dialog template to pass to WinCreateDlg() */ + pTemplate->type = 0; /* Currently always 0. */ + pTemplate->codepage = 0; + pTemplate->offadlgti = 14; /* Offset to array of DLGTITEMs. */ + pTemplate->fsTemplateStatus = 0; /* Reserved field? */ + + /* Index in array of dlg items of item to get focus, */ + /* if 0 then focus goes to first control that can have focus. */ + pTemplate->iItemFocus = 0; + pTemplate->coffPresParams = 0; + + /* First item info - frame */ + + pDlgItem = &pTemplate->adlgti; + pDlgItem->fsItemStatus = 0; /* Reserved? */ + /* Number of dialog item child windows owned by this item. */ + pDlgItem->cChildren = 2 + cSDLBtnData; // Ststic text + buttons. + /* Length of class name, if 0 then offClassname contains a WC_ value. */ + pDlgItem->cchClassName = 0; + pDlgItem->offClassName = (USHORT)WC_FRAME; + /* Length of text. */ + pDlgItem->cchText = cbTitle + 1; /* +1 - trailing ZERO. */ + pDlgItem->offText = pcDlgData - (PCHAR)pTemplate; /* Offset to title text. */ + /* Copy text for the title into the dialog template. */ + if ( pszTitle != NULL ) + strcpy( pcDlgData, pszTitle ); + else + *pcDlgData = '\0'; + pcDlgData += pDlgItem->cchText; + + pDlgItem->flStyle = WS_GROUP | WS_VISIBLE | WS_CLIPSIBLINGS | + FS_DLGBORDER | WS_SAVEBITS; + pDlgItem->x = 100; + pDlgItem->y = 100; + pDlgItem->cx = 175; + pDlgItem->cy = 65; + pDlgItem->id = DID_OK; /* An ID value? */ + if ( pSDLColors == NULL ) + pDlgItem->offPresParams = 0; + else + { + // Presentation parameter for the frame - dialog colors. + pDlgItem->offPresParams = pcDlgData - (PCHAR)pTemplate; + ((PPRESPARAMS)pcDlgData)->cb = 22; + pcDlgData += 4; + ((PPARAM)pcDlgData)->id = PP_FOREGROUNDCOLOR; + ((PPARAM)pcDlgData)->cb = 3; + ((PPARAM)pcDlgData)->ab[0] = pSDLColors[SDL_MESSAGEBOX_COLOR_TEXT].b; + ((PPARAM)pcDlgData)->ab[1] = pSDLColors[SDL_MESSAGEBOX_COLOR_TEXT].g; + ((PPARAM)pcDlgData)->ab[2] = pSDLColors[SDL_MESSAGEBOX_COLOR_TEXT].r; + pcDlgData += 11; + ((PPARAM)pcDlgData)->id = PP_BACKGROUNDCOLOR; + ((PPARAM)pcDlgData)->cb = 3; + ((PPARAM)pcDlgData)->ab[0] = pSDLColors[SDL_MESSAGEBOX_COLOR_BACKGROUND].b; + ((PPARAM)pcDlgData)->ab[1] = pSDLColors[SDL_MESSAGEBOX_COLOR_BACKGROUND].g; + ((PPARAM)pcDlgData)->ab[2] = pSDLColors[SDL_MESSAGEBOX_COLOR_BACKGROUND].r; + pcDlgData += 11; + } + + /* Offset to ctl data. */ + pDlgItem->offCtlData = pcDlgData - (PCHAR)pTemplate; + /* Put CtlData for the dialog in here */ + *((PULONG)pcDlgData) = FCF_TITLEBAR | FCF_SYSMENU; + pcDlgData += sizeof(ULONG); + + /* Second item info - static text (message). */ + + pDlgItem++; + pDlgItem->fsItemStatus = 0; + /* No children since its a control, it could have child control */ + /* (ex. a group box). */ + pDlgItem->cChildren = 0; + /* Length of class name, 0 - offClassname contains a WC_ constant. */ + pDlgItem->cchClassName = 0; + pDlgItem->offClassName = (USHORT)WC_STATIC; + + pDlgItem->cchText = cbText + 1; + pDlgItem->offText = pcDlgData - (PCHAR)pTemplate; /* Offset to the text. */ + /* Copy message text into the dialog template. */ + if ( pszText != NULL ) + strcpy( pcDlgData, pszText ); + else + *pcDlgData = '\0'; + pcDlgData += pDlgItem->cchText; + + pDlgItem->flStyle = SS_TEXT | DT_TOP | DT_LEFT | DT_WORDBREAK | WS_VISIBLE; + // It will be really set in _wmInitDlg(). + pDlgItem->x = 25; + pDlgItem->y = 13; + pDlgItem->cx = 147; + pDlgItem->cy = 62; // It will be used. + + pDlgItem->id = IDD_TEXT_MESSAGE; /* an ID value */ + if ( pSDLColors == NULL ) + pDlgItem->offPresParams = 0; + else + { + // Presentation parameter for the static text - dialog colors. + pDlgItem->offPresParams = pcDlgData - (PCHAR)pTemplate; + ((PPRESPARAMS)pcDlgData)->cb = 22; + pcDlgData += 4; + ((PPARAM)pcDlgData)->id = PP_FOREGROUNDCOLOR; + ((PPARAM)pcDlgData)->cb = 3; + ((PPARAM)pcDlgData)->ab[0] = pSDLColors[SDL_MESSAGEBOX_COLOR_TEXT].b; + ((PPARAM)pcDlgData)->ab[1] = pSDLColors[SDL_MESSAGEBOX_COLOR_TEXT].g; + ((PPARAM)pcDlgData)->ab[2] = pSDLColors[SDL_MESSAGEBOX_COLOR_TEXT].r; + pcDlgData += 11; + ((PPARAM)pcDlgData)->id = PP_BACKGROUNDCOLOR; + ((PPARAM)pcDlgData)->cb = 3; + ((PPARAM)pcDlgData)->ab[0] = pSDLColors[SDL_MESSAGEBOX_COLOR_BACKGROUND].b; + ((PPARAM)pcDlgData)->ab[1] = pSDLColors[SDL_MESSAGEBOX_COLOR_BACKGROUND].g; + ((PPARAM)pcDlgData)->ab[2] = pSDLColors[SDL_MESSAGEBOX_COLOR_BACKGROUND].r; + pcDlgData += 11; + } + pDlgItem->offCtlData = 0; + + /* Third item info - static bitmap. */ + + pDlgItem++; + pDlgItem->fsItemStatus = 0; + pDlgItem->cChildren = 0; + pDlgItem->cchClassName = 0; + pDlgItem->offClassName = (USHORT)WC_STATIC; + + pDlgItem->cchText = 3; // 0xFF, low byte of the icon Id, high byte of icon Id. + pDlgItem->offText = pcDlgData - (PCHAR)pTemplate; /* Offset to the Id. */ + /* Write susyem icon ID into dialog template. */ + *pcDlgData = 0xFF; // First byte is 0xFF - next 2 bytes is system pointer Id. + pcDlgData++; + *((PUSHORT)pcDlgData) = + (messageboxdata->flags & SDL_MESSAGEBOX_ERROR) != 0 + ? SPTR_ICONERROR + : (messageboxdata->flags & SDL_MESSAGEBOX_WARNING) != 0 + ? SPTR_ICONWARNING : SPTR_ICONINFORMATION; + pcDlgData += 2; + + pDlgItem->flStyle = SS_SYSICON | WS_VISIBLE; + + pDlgItem->x = 4; + pDlgItem->y = 45; // It will be really set in _wmInitDlg(). + pDlgItem->cx = 0; + pDlgItem->cy = 0; + + pDlgItem->id = IDD_BITMAP; + pDlgItem->offPresParams = 0; + pDlgItem->offCtlData = 0; + + /* Next items - buttons. */ + + for( ulIdx = 0; ulIdx < cSDLBtnData; ulIdx++ ) + { + pDlgItem++; + + pDlgItem->fsItemStatus = 0; + pDlgItem->cChildren = 0; /* No children. */ + pDlgItem->cchClassName = 0; /* 0 - offClassname is WC_ constant. */ + pDlgItem->offClassName = (USHORT)WC_BUTTON; + + pszBtnText = OS2_UTF8ToSys( (PSZ)pSDLBtnData[ulIdx].text ); + cbBtnText = ( pszBtnText == NULL ? + 0 : strlen( pszBtnText ) ); + pDlgItem->cchText = cbBtnText + 1; + pDlgItem->offText = pcDlgData - (PCHAR)pTemplate; /* Offset to the text. */ + /* Copy text for the button into the dialog template. */ + if ( pszBtnText != NULL ) + strcpy( pcDlgData, pszBtnText ); + else + *pcDlgData = '\0'; + pcDlgData += pDlgItem->cchText; + SDL_free( pszBtnText ); + + pDlgItem->flStyle = BS_PUSHBUTTON | WS_TABSTOP | WS_VISIBLE; + if ( pSDLBtnData[ulIdx].flags == SDL_MESSAGEBOX_BUTTON_RETURNKEY_DEFAULT ) + { + pDlgItem->flStyle |= BS_DEFAULT; + pTemplate->iItemFocus = ulIdx + 3; // +3 - frame, static text and icon. + pSDLColor = &pSDLColors[SDL_MESSAGEBOX_COLOR_BUTTON_SELECTED]; + } + else + pSDLColor = &pSDLColors[SDL_MESSAGEBOX_COLOR_TEXT]; + + // It will be really set in _wmInitDlg() + pDlgItem->x = 10; + pDlgItem->y = 10; + pDlgItem->cx = 70; + pDlgItem->cy = 15; + + pDlgItem->id = IDD_PB_FIRST + ulIdx; /* an ID value */ + if ( pSDLColors == NULL ) + pDlgItem->offPresParams = 0; + else + { + // Presentation parameter for the button - dialog colors. + pDlgItem->offPresParams = pcDlgData - (PCHAR)pTemplate; + ((PPRESPARAMS)pcDlgData)->cb = 44; + pcDlgData += 4; + ((PPARAM)pcDlgData)->id = PP_FOREGROUNDCOLOR; + ((PPARAM)pcDlgData)->cb = 3; + ((PPARAM)pcDlgData)->ab[0] = pSDLColor->b; + ((PPARAM)pcDlgData)->ab[1] = pSDLColor->g; + ((PPARAM)pcDlgData)->ab[2] = pSDLColor->r; + pcDlgData += 11; + ((PPARAM)pcDlgData)->id = PP_BACKGROUNDCOLOR; + ((PPARAM)pcDlgData)->cb = 3; + ((PPARAM)pcDlgData)->ab[0] = pSDLColors[SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND].b; + ((PPARAM)pcDlgData)->ab[1] = pSDLColors[SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND].g; + ((PPARAM)pcDlgData)->ab[2] = pSDLColors[SDL_MESSAGEBOX_COLOR_BUTTON_BACKGROUND].r; + pcDlgData += 11; + ((PPARAM)pcDlgData)->id = PP_BORDERLIGHTCOLOR; + ((PPARAM)pcDlgData)->cb = 3; + ((PPARAM)pcDlgData)->ab[0] = pSDLColors[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].b; + ((PPARAM)pcDlgData)->ab[1] = pSDLColors[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].g; + ((PPARAM)pcDlgData)->ab[2] = pSDLColors[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].r; + pcDlgData += 11; + ((PPARAM)pcDlgData)->id = PP_BORDERDARKCOLOR; + ((PPARAM)pcDlgData)->cb = 3; + ((PPARAM)pcDlgData)->ab[0] = pSDLColors[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].b; + ((PPARAM)pcDlgData)->ab[1] = pSDLColors[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].g; + ((PPARAM)pcDlgData)->ab[2] = pSDLColors[SDL_MESSAGEBOX_COLOR_BUTTON_BORDER].r; + pcDlgData += 11; + } + pDlgItem->offCtlData = 0; + } + // Check, end of templ. data: &((PCHAR)pTemplate)[cbTemplate] == pcDlgData + + // Create the dialog from template. + + stDlgData.cb = sizeof(MSGBOXDLGDATA); + stDlgData.hwndUnder = ( messageboxdata->window != NULL ) && + ( messageboxdata->window->driverdata != NULL ) + ? ((PWINDATA)messageboxdata->window->driverdata)->hwnd + : HWND_DESKTOP; + + hwnd = WinCreateDlg( HWND_DESKTOP, // Parent is desktop. + stDlgData.hwndUnder, + (PFNWP)DynDlgProc, pTemplate, &stDlgData ); + SDL_free( pTemplate ); + SDL_free( pszTitle ); + SDL_free( pszText ); + + return hwnd; +} + + +int OS2_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid) +{ + HWND hwnd; + ULONG ulRC; + SDL_MessageBoxButtonData + *pSDLBtnData = + (SDL_MessageBoxButtonData *)messageboxdata->buttons; + ULONG cSDLBtnData = messageboxdata->numbuttons; + BOOL fVideoInitialized = SDL_WasInit( SDL_INIT_VIDEO ); + HAB hab; + HMQ hmq; + BOOL fSuccess = FALSE; + + if ( !fVideoInitialized ) + { + PTIB tib; + PPIB pib; + + 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. + } + + hab = WinInitialize( 0 ); + if ( hab == NULLHANDLE ) + { + debug( "WinInitialize() failed" ); + return -1; + } + hmq = WinCreateMsgQueue( hab, 0 ); + if ( hmq == NULLHANDLE ) + { + debug( "WinCreateMsgQueue() failed" ); + return -1; + } + } + + // Create dynamic dialog. + hwnd = _makeDlg( messageboxdata ); + // Show dialog and obtain button Id. + ulRC = WinProcessDlg( hwnd ); + // Destroy dialog, + WinDestroyWindow( hwnd ); + + if ( ulRC == DID_CANCEL ) + { + // Window closed by ESC, Alt+F4 or system menu. + ULONG ulIdx; + + for( ulIdx = 0; ulIdx < cSDLBtnData; ulIdx++, pSDLBtnData++ ) + { + if ( pSDLBtnData->flags == SDL_MESSAGEBOX_BUTTON_ESCAPEKEY_DEFAULT ) + { + *buttonid = pSDLBtnData->buttonid; + fSuccess = TRUE; + break; + } + } + } + else + { + // Button pressed. + ulRC -= IDD_PB_FIRST; + if ( ulRC < cSDLBtnData ) + { + *buttonid = pSDLBtnData[ulRC].buttonid; + fSuccess = TRUE; + } + } + + if ( !fVideoInitialized ) + { + WinDestroyMsgQueue( hmq ); + WinTerminate( hab ); + } + + return fSuccess ? 0 : -1; +} + +#endif /* SDL_VIDEO_DRIVER_OS2 */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/os2/SDL_os2messagebox.h b/src/video/os2/SDL_os2messagebox.h new file mode 100644 index 000000000..bd2fdf7e1 --- /dev/null +++ b/src/video/os2/SDL_os2messagebox.h @@ -0,0 +1,29 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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 + +extern int OS2_ShowMessageBox(const SDL_MessageBoxData *messageboxdata, int *buttonid); + +#endif /* SDL_VIDEO_DRIVER_OS2 */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/os2/SDL_os2mouse.c b/src/video/os2/SDL_os2mouse.c new file mode 100644 index 000000000..67d3f1cb3 --- /dev/null +++ b/src/video/os2/SDL_os2mouse.c @@ -0,0 +1,204 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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_os2video.h" +#include "../../events/SDL_mouse_c.h" +#include "SDL_os2util.h" + +HPOINTER hptrCursor = NULLHANDLE; + +static SDL_Cursor* OS2_CreateCursor(SDL_Surface *surface, int hot_x, int hot_y) +{ + ULONG ulMaxW = WinQuerySysValue( HWND_DESKTOP, SV_CXPOINTER ); + ULONG ulMaxH = WinQuerySysValue( HWND_DESKTOP, SV_CYPOINTER ); + HPOINTER hptr; + SDL_Cursor *pSDLCursor; + + if ( ( surface->w > ulMaxW ) || ( surface->h > ulMaxH ) ) + { + debug( "Given image size is %u x %u, maximum allowed size is %u x %u", + surface->w, surface->h, ulMaxW, ulMaxH ); + return NULL; + } + + hptr = utilCreatePointer( surface, hot_x, ulMaxH - hot_y - 1 ); + if ( hptr == NULLHANDLE ) + return NULL; + + pSDLCursor = SDL_calloc( 1, sizeof(SDL_Cursor) ); + if ( pSDLCursor == NULL ) + { + WinDestroyPointer( hptr ); + SDL_OutOfMemory(); + return NULL; + } + + pSDLCursor->driverdata = (void *)hptr; + return pSDLCursor; +} + +static SDL_Cursor* OS2_CreateSystemCursor(SDL_SystemCursor id) +{ + SDL_Cursor* pSDLCursor; + LONG lSysId; + HPOINTER hptr; + + switch( id ) + { + case SDL_SYSTEM_CURSOR_ARROW: lSysId = SPTR_ARROW; break; + case SDL_SYSTEM_CURSOR_IBEAM: lSysId = SPTR_TEXT; break; + case SDL_SYSTEM_CURSOR_WAIT: lSysId = SPTR_WAIT; break; + case SDL_SYSTEM_CURSOR_CROSSHAIR: lSysId = SPTR_MOVE; break; + case SDL_SYSTEM_CURSOR_WAITARROW: lSysId = SPTR_WAIT; break; + case SDL_SYSTEM_CURSOR_SIZENWSE: lSysId = SPTR_SIZENWSE; break; + case SDL_SYSTEM_CURSOR_SIZENESW: lSysId = SPTR_SIZENESW; break; + case SDL_SYSTEM_CURSOR_SIZEWE: lSysId = SPTR_SIZEWE; break; + case SDL_SYSTEM_CURSOR_SIZENS: lSysId = SPTR_SIZENS; break; + case SDL_SYSTEM_CURSOR_SIZEALL: lSysId = SPTR_MOVE; break; + case SDL_SYSTEM_CURSOR_NO: lSysId = SPTR_ILLEGAL; break; + case SDL_SYSTEM_CURSOR_HAND: lSysId = SPTR_ARROW; break; + default: + debug( "Unknown cursor id: %u", id ); + return NULL; + } + + // On eCS SPTR_WAIT for last paramether fCopy=TRUE/FALSE gives different + // "wait" icons. -=8( ) + hptr = WinQuerySysPointer( HWND_DESKTOP, lSysId, + id == SDL_SYSTEM_CURSOR_WAIT ); + if ( hptr == NULLHANDLE ) + { + debug( "Cannot load OS/2 system pointer %u for SDL cursor id %u", + lSysId, id ); + return NULL; + } + + pSDLCursor = SDL_calloc( 1, sizeof(SDL_Cursor) ); + if ( pSDLCursor == NULL ) + { + WinDestroyPointer( hptr ); + SDL_OutOfMemory(); + return NULL; + } + + pSDLCursor->driverdata = (void *)hptr; + return pSDLCursor; +} + +static void OS2_FreeCursor(SDL_Cursor *cursor) +{ + HPOINTER hptr = (HPOINTER)cursor->driverdata; + + WinDestroyPointer( hptr ); + SDL_free( cursor ); +} + +static int OS2_ShowCursor(SDL_Cursor *cursor) +{ + hptrCursor = cursor != NULL ? (HPOINTER)cursor->driverdata : NULLHANDLE; + + return ( ( SDL_GetMouseFocus() == NULL ) || + WinSetPointer( HWND_DESKTOP, hptrCursor ) ) ? 0 : -1; +} + +static void OS2_WarpMouse(SDL_Window * window, int x, int y) +{ + PWINDATA pWinData = (PWINDATA)window->driverdata; + POINTL pointl; + + pointl.x = x; + pointl.y = window->h - y; + WinMapWindowPoints( pWinData->hwnd, HWND_DESKTOP, &pointl, 1 ); +// pWinData->lSkipWMMouseMove++; ??? + WinSetPointerPos( HWND_DESKTOP, pointl.x, pointl.y ); +} + +static int OS2_WarpMouseGlobal(int x, int y) +{ + WinSetPointerPos( HWND_DESKTOP, x, + WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN ) - y ); + return 0; +} + +static int OS2_CaptureMouse(SDL_Window *window) +{ + return WinSetCapture( HWND_DESKTOP, + window == NULL ? NULLHANDLE + : ((PWINDATA)window->driverdata)->hwnd ) + ? 0 : -1; +} + +static Uint32 OS2_GetGlobalMouseState(int *x, int *y) +{ + POINTL pointl; + ULONG ulRes; + + WinQueryPointerPos( HWND_DESKTOP, &pointl ); + *x = pointl.x; + *y = WinQuerySysValue( HWND_DESKTOP, SV_CYSCREEN ) - pointl.y - 1; + + ulRes = WinGetKeyState( HWND_DESKTOP, VK_BUTTON1 ) & 0x8000 + ? SDL_BUTTON_LMASK : 0; + if ( WinGetKeyState( HWND_DESKTOP, VK_BUTTON2 ) & 0x8000 ) + ulRes |= SDL_BUTTON_RMASK; + if ( WinGetKeyState( HWND_DESKTOP, VK_BUTTON3 ) & 0x8000 ) + ulRes |= SDL_BUTTON_MMASK; + + return ulRes; +} + + +void OS2_InitMouse(_THIS, ULONG hab) +{ + SDL_Mouse *pSDLMouse = SDL_GetMouse(); + + pSDLMouse->CreateCursor = OS2_CreateCursor; + pSDLMouse->CreateSystemCursor = OS2_CreateSystemCursor; + pSDLMouse->ShowCursor = OS2_ShowCursor; + pSDLMouse->FreeCursor = OS2_FreeCursor; + pSDLMouse->WarpMouse = OS2_WarpMouse; + pSDLMouse->WarpMouseGlobal = OS2_WarpMouseGlobal; + pSDLMouse->CaptureMouse = OS2_CaptureMouse; + pSDLMouse->GetGlobalMouseState = OS2_GetGlobalMouseState; + + SDL_SetDefaultCursor( OS2_CreateSystemCursor( SDL_SYSTEM_CURSOR_ARROW ) ); + if ( hptrCursor == NULLHANDLE ) + hptrCursor = WinQuerySysPointer( HWND_DESKTOP, SPTR_ARROW, TRUE ); + + SDL_SetDoubleClickTime( WinQuerySysValue( HWND_DESKTOP, SV_DBLCLKTIME ) ); +} + +void OS2_QuitMouse(_THIS) +{ + SDL_Mouse *pSDLMouse = SDL_GetMouse(); + + if ( pSDLMouse->def_cursor != NULL ) + { + SDL_free( pSDLMouse->def_cursor ); + pSDLMouse->def_cursor = NULL; + pSDLMouse->cur_cursor = NULL; + } +} + +#endif /* SDL_VIDEO_DRIVER_OS2 */ diff --git a/src/video/os2/SDL_os2mouse.h b/src/video/os2/SDL_os2mouse.h new file mode 100644 index 000000000..82189a880 --- /dev/null +++ b/src/video/os2/SDL_os2mouse.h @@ -0,0 +1,33 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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" + +#ifndef _SDL_os2mouse_h +#define _SDL_os2mouse_h + +extern HPOINTER hptrCursor; + +extern void OS2_InitMouse(_THIS, ULONG hab); +extern void OS2_QuitMouse(_THIS); + +#endif /* _SDL_os2mouse_h */ + +/* vi: set ts=4 sw=4 expandtab: */ diff --git a/src/video/os2/SDL_os2output.h b/src/video/os2/SDL_os2output.h new file mode 100644 index 000000000..0e90c4f82 --- /dev/null +++ b/src/video/os2/SDL_os2output.h @@ -0,0 +1,54 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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. +*/ +#ifndef _SDL_os2output_ +#define _SDL_os2output_ + +#include ".\core\os2\SDL_os2.h" + +typedef struct _VODATA *PVODATA; + +typedef struct _VIDEOOUTPUTINFO { + ULONG ulBPP; + ULONG fccColorEncoding; + ULONG ulScanLineSize; + ULONG ulHorizResolution; + ULONG ulVertResolution; +} VIDEOOUTPUTINFO, *PVIDEOOUTPUTINFO; + +typedef struct _OS2VIDEOOUTPUT { + BOOL (*QueryInfo)(PVIDEOOUTPUTINFO pInfo); + PVODATA (*Open)(); + VOID (*Close)(PVODATA pVOData); + BOOL (*SetVisibleRegion)(PVODATA pVOData, HWND hwnd, + SDL_DisplayMode *pSDLDisplayMode, HRGN hrgnShape, + BOOL fVisible); + PVOID (*VideoBufAlloc)(PVODATA pVOData, ULONG ulWidth, ULONG ulHeight, + ULONG ulBPP, ULONG fccColorEncoding, + PULONG pulScanLineSize); + VOID (*VideoBufFree)(PVODATA pVOData); + BOOL (*Update)(PVODATA pVOData, HWND hwnd, SDL_Rect *pSDLRects, + ULONG cSDLRects); +} OS2VIDEOOUTPUT, *POS2VIDEOOUTPUT; + +extern OS2VIDEOOUTPUT voDive; +extern OS2VIDEOOUTPUT voVMan; + +#endif // _SDL_os2output_ diff --git a/src/video/os2/SDL_os2util.c b/src/video/os2/SDL_os2util.c new file mode 100644 index 000000000..d5429f54f --- /dev/null +++ b/src/video/os2/SDL_os2util.c @@ -0,0 +1,118 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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_os2util.h" + + +HPOINTER utilCreatePointer(SDL_Surface *surface, ULONG ulHotX, ULONG ulHotY) +{ + HBITMAP hbm; + BITMAPINFOHEADER2 bmih = { 0 }; + BITMAPINFO bmi = { 0 }; + HPS hps; + PULONG pulBitmap; + PULONG pulDst, pulSrc, pulDstMask; + ULONG ulY, ulX; + HPOINTER hptr = NULLHANDLE; + + if ( surface->format->format != SDL_PIXELFORMAT_ARGB8888 ) + { + debug( "Image format should be SDL_PIXELFORMAT_ARGB8888" ); + return NULLHANDLE; + } + + pulBitmap = SDL_malloc( surface->h * surface->w * 4 * 2 ); + if ( pulBitmap == NULL ) + { + SDL_OutOfMemory(); + return NULLHANDLE; + } + + // pulDst - last line of surface (image) part of the result bitmap's + pulDst = &pulBitmap[ (surface->h - 1) * surface->w ]; + // pulDstMask - last line of mask part of the result bitmap's + pulDstMask = &pulBitmap[ (2 * surface->h - 1) * surface->w ]; + // pulSrc - first line of source image + pulSrc = (PULONG)surface->pixels; + + for( ulY = 0; ulY < surface->h; ulY++ ) + { + for( ulX = 0; ulX < surface->w; ulX++ ) + { + if ( (pulSrc[ulX] & 0xFF000000) == 0 ) + { + pulDst[ulX] = 0; + pulDstMask[ulX] = 0xFFFFFFFF; + } + else + { + pulDst[ulX] = pulSrc[ulX] & 0xFFFFFF; + pulDstMask[ulX] = 0; + } + } + + // Set image and mask pointers on one line up + pulDst -= surface->w; + pulDstMask -= surface->w; + // Set source image pointer to the next line + pulSrc = (PULONG)( ((PCHAR)pulSrc) + surface->pitch ); + } + + // Create system bitmap object. + + bmih.cbFix = sizeof(BITMAPINFOHEADER2); + bmih.cx = surface->w; + bmih.cy = 2 * surface->h; + bmih.cPlanes = 1; + bmih.cBitCount = 32; + bmih.ulCompression = BCA_UNCOMP; + bmih.cbImage = bmih.cx * bmih.cy * 4; + + bmi.cbFix = sizeof(BITMAPINFOHEADER); + bmi.cx = bmih.cx; + bmi.cy = bmih.cy; + bmi.cPlanes = 1; + bmi.cBitCount = 32; + + hps = WinGetPS( HWND_DESKTOP ); + hbm = GpiCreateBitmap( hps, (PBITMAPINFOHEADER2)&bmih, CBM_INIT, + (PBYTE)pulBitmap, (PBITMAPINFO2)&bmi ); + if ( hbm == GPI_ERROR ) + debug( "GpiCreateBitmap() failed" ); + else + { + // Create a system pointer object. + hptr = WinCreatePointer( HWND_DESKTOP, hbm, TRUE, ulHotX, ulHotY ); + if ( hptr == NULLHANDLE ) + debug( "WinCreatePointer() failed" ); + } + GpiDeleteBitmap( hbm ); + + WinReleasePS( hps ); + SDL_free( pulBitmap ); + + return hptr; +} + +#endif /* SDL_VIDEO_DRIVER_OS2 */ diff --git a/src/video/os2/SDL_os2util.h b/src/video/os2/SDL_os2util.h new file mode 100644 index 000000000..6aac3fd25 --- /dev/null +++ b/src/video/os2/SDL_os2util.h @@ -0,0 +1,38 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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. +*/ + +#ifndef _SDL_os2util_h +#define _SDL_os2util_h + +#include "SDL_log.h" +#include "../SDL_sysvideo.h" +#include "../../core/os2/SDL_os2.h" + +#define INCL_WIN +#define INCL_GPI +#include + +/*#define debug(s,...) SDL_LogDebug( SDL_LOG_CATEGORY_VIDEO, \ + __func__"(): "##s, ##__VA_ARGS__ )*/ + +HPOINTER utilCreatePointer(SDL_Surface *surface, ULONG ulHotX, ULONG ulHotY); + +#endif // _SDL_os2util_h diff --git a/src/video/os2/SDL_os2video.c b/src/video/os2/SDL_os2video.c new file mode 100644 index 000000000..c6f5b7a34 --- /dev/null +++ b/src/video/os2/SDL_os2video.c @@ -0,0 +1,1786 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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_ +#include +#include + +#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( "No display for the window" ); + return FALSE; + } + + return &pSDLDisplay->current_mode; +} + + +static VOID _mouseCheck(PWINDATA pWinData) +{ + SDL_Mouse *pSDLMouse = SDL_GetMouse(); + + if ( ( pSDLMouse->relative_mode || + (pWinData->window->flags & SDL_WINDOW_INPUT_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(PWINDATA pWinData, BOOL fVisible) +{ + SDL_VideoDisplay *pSDLDisplay; + + if ( pWinData->pVOData == NULL ) + 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(PWINDATA 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(PWINDATA 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_INPUT_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(PWINDATA 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_INPUT_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(PWINDATA 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(PWINDATA 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(PWINDATA 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(PWINDATA 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( 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 ); + + return (MRESULT)FALSE; +} + +MRESULT EXPENTRY wndFrameProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) +{ + HWND hwndClient = WinQueryWindow( hwnd, QW_BOTTOM ); + PWINDATA pWinData = (PWINDATA)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; + int 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) +{ + PWINDATA pWinData = (PWINDATA)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) +{ + PSDL_VideoData pVData = (PSDL_VideoData)_this->driverdata; + QMSG qmsg; + + if( WinPeekMsg( pVData->hab, &qmsg, NULLHANDLE, 0, 0, PM_REMOVE ) ) + WinDispatchMsg( pVData->hab, &qmsg ); +} + +static PWINDATA _setupWindow(_THIS, SDL_Window *window, HWND hwndFrame, + HWND hwnd) +{ + PSDL_VideoData pVData = (PSDL_VideoData)_this->driverdata; + PWINDATA 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; + PWINDATA 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) +{ + PSDL_VideoData pVData = (PSDL_VideoData)_this->driverdata; + CHAR acBuf[256]; + CLASSINFO stCI; + HWND hwndUser = (HWND)data; + HWND hwndFrame, hwnd; + ULONG cbText; + PSZ pszText; + PWINDATA pWinData; + SDL_DisplayMode *pSDLDisplayMode = _getDisplayModeForSDLWindow( window ); + SWP swp; + POINTL pointl; + + debug( "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) +{ + PSDL_VideoData pVData = (PSDL_VideoData)_this->driverdata; + PWINDATA pWinData = (PWINDATA)window->driverdata; + + debug( "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( ((PWINDATA)window->driverdata)->hwndFrame, pszTitle ); + SDL_free( pszTitle ); +} + +static void OS2_SetWindowIcon(_THIS, SDL_Window *window, SDL_Surface *icon) +{ + PWINDATA pWinData = (PWINDATA)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( "Cannot set icon for the window" ); +} + +static void OS2_SetWindowPosition(_THIS, SDL_Window *window) +{ + PWINDATA pWinData = (PWINDATA)window->driverdata; + RECTL rectl; + ULONG ulFlags; + SDL_DisplayMode *pSDLDisplayMode = _getDisplayModeForSDLWindow( window ); + + debug( "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( "Enter" ); + OS2_SetWindowPosition( _this, window ); +} + +static void OS2_ShowWindow(_THIS, SDL_Window *window) +{ + PWINDATA pWinData = (PWINDATA)window->driverdata; + + debug( "Enter" ); + WinShowWindow( pWinData->hwndFrame, TRUE ); +} + +static void OS2_HideWindow(_THIS, SDL_Window *window) +{ + PWINDATA pWinData = (PWINDATA)window->driverdata; + + debug( "Enter" ); + WinShowWindow( pWinData->hwndFrame, FALSE ); +} + +static void OS2_RaiseWindow(_THIS, SDL_Window *window) +{ + debug( "Enter" ); + OS2_SetWindowPosition( _this, window ); +} + +static void OS2_MaximizeWindow(_THIS, SDL_Window *window) +{ + PWINDATA pWinData = (PWINDATA)window->driverdata; + + debug( "Enter" ); + WinSetWindowPos( pWinData->hwndFrame, HWND_TOP, 0, 0, 0, 0, SWP_MAXIMIZE ); +} + +static void OS2_MinimizeWindow(_THIS, SDL_Window *window) +{ + PWINDATA pWinData = (PWINDATA)window->driverdata; + + debug( "Enter" ); + WinSetWindowPos( pWinData->hwndFrame, HWND_TOP, 0, 0, 0, 0, + SWP_MINIMIZE | SWP_DEACTIVATE ); +} + +static void OS2_RestoreWindow(_THIS, SDL_Window *window) +{ + PWINDATA pWinData = (PWINDATA)window->driverdata; + + debug( "Enter" ); + WinSetWindowPos( pWinData->hwndFrame, HWND_TOP, 0, 0, 0, 0, + SWP_RESTORE ); +} + +static void OS2_SetWindowBordered(_THIS, SDL_Window * window, + SDL_bool bordered) +{ + PWINDATA pWinData = (PWINDATA)window->driverdata; + ULONG ulStyle = WinQueryWindowULong( pWinData->hwndFrame, QWL_STYLE ); + RECTL rectl; + + debug( "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; + PWINDATA pWinData = (PWINDATA)window->driverdata; + SDL_DisplayMode *pSDLDisplayMode = &display->current_mode; + + debug( "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( "WinCalcFrameRect() failed" ); + else if ( !WinSetWindowPos( pWinData->hwndFrame, HWND_TOP, + rectl.xLeft, rectl.yBottom, + rectl.xRight - rectl.xLeft, rectl.yTop - rectl.yBottom, + ulFlags ) ) + debug( "WinSetWindowPos() failed" ); +} + +static SDL_bool OS2_GetWindowWMInfo(_THIS, SDL_Window * window, + struct SDL_SysWMinfo *info) +{ + PWINDATA pWinData = (PWINDATA)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( "Enter" ); + return 0; +} + +static void OS2_SetWindowGrab(_THIS, SDL_Window *window, SDL_bool grabbed) +{ + PWINDATA pWinData = (PWINDATA)window->driverdata; + + debug( "Enter, %u", grabbed ); + _mouseCheck( pWinData ); +} + + +// Shaper. + +typedef struct _SHAPERECTS { + PRECTL pRects; + ULONG cRects; + ULONG ulWinHeight; +} SHAPERECTS, *PSHAPERECTS; + +static void _combineRectRegions(SDL_ShapeTree *node, void *closure) +{ + PSHAPERECTS pShapeRects = (PSHAPERECTS)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( "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; + PWINDATA pWinData; + SHAPERECTS stShapeRects = { 0 }; + HPS hps; + + debug( "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 = (PWINDATA)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( "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) +{ + PWINDATA pWinData = (PWINDATA)window->driverdata; + + debug( "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) +{ + PWINDATA pWinData = (PWINDATA)window->driverdata; + SDL_VideoDisplay *pSDLDisplay = SDL_GetDisplayForWindow( window ); + SDL_DisplayMode *pSDLDisplayMode; + PMODEDATA pModeData; + ULONG ulWidth, ulHeight; + + debug( "Enter" ); + + if ( pSDLDisplay == NULL ) + { + debug( "No display for the window" ); + return -1; + } + + pSDLDisplayMode = &pSDLDisplay->current_mode; + pModeData = (PMODEDATA)pSDLDisplayMode->driverdata; + if ( pModeData == NULL ) + return SDL_SetError( "No mode data for the display" ); + + SDL_GetWindowSize( window, (int *)&ulWidth, (int *)&ulHeight ); + debug( "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( "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) +{ + PWINDATA pWinData = (PWINDATA)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) +{ + PSDL_VideoData pVData = (PSDL_VideoData)_this->driverdata; + PSZ pszClipboard; + PSZ pszText = text == NULL ? NULL : OS2_UTF8ToSys( text ); + ULONG cbText; + ULONG ulRC; + BOOL fSuccess; + + debug( "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( "DosAllocSharedMem() failed, rc = %u", ulRC ); + SDL_free( pszText ); + return -1; + } + + strcpy( pszClipboard, pszText ); + SDL_free( pszText ); + + if ( !WinOpenClipbrd( pVData->hab ) ) + { + debug( "WinOpenClipbrd() failed" ); + fSuccess = FALSE; + } + else + { + WinEmptyClipbrd( pVData->hab ); + + fSuccess = WinSetClipbrdData( pVData->hab, (ULONG)pszClipboard, CF_TEXT, + CFI_POINTER ); + if ( !fSuccess ) + debug( "WinOpenClipbrd() failed" ); + + WinCloseClipbrd( pVData->hab ); + } + + if ( !fSuccess ) + { + DosFreeMem( pszClipboard ); + return -1; + } + + return 0; +} + +static char *OS2_GetClipboardText(_THIS) +{ + PSDL_VideoData pVData = (PSDL_VideoData)_this->driverdata; + PSZ pszClipboard = NULL; + + if ( !WinOpenClipbrd( pVData->hab ) ) + debug( "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) +{ + PSDL_VideoData pVData = (PSDL_VideoData)_this->driverdata; + SDL_bool fClipboard; + + if ( !WinOpenClipbrd( pVData->hab ) ) + { + debug( "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) +{ + PSDL_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(PSDL_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; + PDISPLAYDATA pDisplayData; + PMODEDATA pModeData; + VIDEOOUTPUTINFO stVOInfo; + + if ( !pVData->pOutput->QueryInfo( &stVOInfo ) ) + { + SDL_free( pVData ); + return SDL_SetError( "Video mode query failed." ); + } + + 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 ); + } + + OS2_InitMouse( _this, pVData->hab ); + + return 0; +} + +static void OS2_VideoQuit(_THIS) +{ + PSDL_VideoData pVData = (PSDL_VideoData)_this->driverdata; + ULONG ulDisplayIdx, ulModeIdx; + SDL_VideoDisplay *pSDLDisplay; + + OS2_QuitMouse( _this ); + + WinDestroyMsgQueue( pVData->hmq ); + WinTerminate( pVData->hab ); + + // We support only one display. Free all listed displays data for the future. + for( ulDisplayIdx = 0; ulDisplayIdx < _this->num_displays; ulDisplayIdx++ ) + { + pSDLDisplay = &_this->displays[ulDisplayIdx]; + + // Free video mode data (PMODEDATA). + if ( pSDLDisplay->desktop_mode.driverdata != NULL ) + SDL_free( pSDLDisplay->desktop_mode.driverdata ); + + // We support only one mode - desktop_mode. Free all modes for the future. + for( ulModeIdx = 0; ulModeIdx < pSDLDisplay->num_display_modes; + ulModeIdx++ ) + if ( pSDLDisplay->display_modes[ulModeIdx].driverdata != NULL ) + SDL_free( pSDLDisplay->display_modes[ulModeIdx].driverdata ); + + // Free display data (PDISPLAYDATA). + if ( pSDLDisplay->driverdata != NULL ) + { + SDL_free( pSDLDisplay->driverdata ); + pSDLDisplay->driverdata = NULL; + } + } +} + +static int OS2_GetDisplayBounds(_THIS, SDL_VideoDisplay *display, + SDL_Rect *rect) +{ + debug( "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) +{ + PDISPLAYDATA pDisplayData = (PDISPLAYDATA)display->driverdata; + + debug( "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( "Enter" ); +} + +static int OS2_SetDisplayMode(_THIS, SDL_VideoDisplay *display, + SDL_DisplayMode *mode) +{ + debug( "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 (0); + } + + /* Set the function pointers */ + device->VideoInit = OS2_VideoInit; + device->VideoQuit = OS2_VideoQuit; + device->SetDisplayMode = OS2_SetDisplayMode; + device->GetDisplayBounds = OS2_GetDisplayBounds; + device->GetDisplayDPI = OS2_GetDisplayDPI; + device->GetDisplayModes = OS2_GetDisplayModes; + device->SetDisplayMode = OS2_SetDisplayMode; + device->PumpEvents = OS2_PumpEvents; + device->CreateWindow = OS2_CreateWindow; + device->CreateWindowFrom = 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->SetWindowGrab = OS2_SetWindowGrab; + 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; +} + + +// Output video system availability checking. + +static int OS2DIVE_Available(void) +{ + VIDEOOUTPUTINFO stVOInfo; + + return voDive.QueryInfo( &stVOInfo ); +} + +static int OS2VMAN_Available(void) +{ + VIDEOOUTPUTINFO stVOInfo; + + return voVMan.QueryInfo( &stVOInfo ); +} + + +// 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_Available, OS2_CreateDevice +}; + +VideoBootStrap OS2VMAN_bootstrap = +{ + OS2DRIVER_NAME_VMAN, "OS/2 video driver", + OS2VMAN_Available, OS2_CreateDevice +}; + +#endif /* SDL_VIDEO_DRIVER_OS2 */ diff --git a/src/video/os2/SDL_os2video.h b/src/video/os2/SDL_os2video.h new file mode 100644 index 000000000..633efa25d --- /dev/null +++ b/src/video/os2/SDL_os2video.h @@ -0,0 +1,83 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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" + +#ifndef _SDL_os2video_h +#define _SDL_os2video_h + +#include "../SDL_sysvideo.h" +#include ".\core\os2\SDL_os2.h" + +#define INCL_DOS +#define INCL_DOSERRORS +#define INCL_DOSPROCESS +#define INCL_WIN +#define INCL_GPI +#define INCL_OS2MM +#define INCL_DOSMEMMGR +#include +//#include // Defines FOURCC_xxxx + + +#include "SDL_os2mouse.h" +#include "SDL_os2output.h" + +typedef struct SDL_VideoData { + HAB hab; + HMQ hmq; + POS2VIDEOOUTPUT pOutput; // Video output routines. +} SDL_VideoData, *PSDL_VideoData; + +typedef struct _WINDATA { + SDL_Window *window; + POS2VIDEOOUTPUT pOutput; // Video output routines. + HWND hwndFrame; + HWND hwnd; + PFNWP fnUserWndProc; + PFNWP fnWndFrameProc; + + PVODATA pVOData; // Video output data. + + HRGN hrgnShape; + HPOINTER hptrIcon; + RECTL rectlBeforeFS; + + LONG lSkipWMSize; + LONG lSkipWMMove; + LONG lSkipWMMouseMove; + LONG lSkipWMVRNEnabled; + LONG lSkipWMAdjustFramePos; +} WINDATA, *PWINDATA; + +typedef struct _DISPLAYDATA { + ULONG ulDPIHor; + ULONG ulDPIVer; + ULONG ulDPIDiag; +} DISPLAYDATA, *PDISPLAYDATA; + +typedef struct _MODEDATA { + ULONG ulDepth; + ULONG fccColorEncoding; + ULONG ulScanLineBytes; +} MODEDATA, *PMODEDATA; + + +#endif /* _SDL_os2video_h */ diff --git a/src/video/os2/SDL_os2vman.c b/src/video/os2/SDL_os2vman.c new file mode 100644 index 000000000..394c69553 --- /dev/null +++ b/src/video/os2/SDL_os2vman.c @@ -0,0 +1,512 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2016 Sam Lantinga + + 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" +#include "../SDL_sysvideo.h" +#define INCL_DOSERRORS +#define INCL_DOSPROCESS +#define INCL_DOSMODULEMGR +#define INCL_WIN +#define INCL_GPI +#define INCL_GPIBITMAPS // GPI bit map functions +#include +#define INCL_GRE_DEVICE +#define INCL_GRE_DEVMISC +#include +#include "SDL_os2output.h" +#include "gradd.h" +#include "SDL_os2video.h" + +typedef struct _VODATA { + PVOID pBuffer; + HRGN hrgnVisible; + ULONG ulBPP; + ULONG ulScanLineSize; + ULONG ulWidth; + ULONG ulHeight; + ULONG ulScreenHeight; + ULONG ulScreenBytesPerLine; + RECTL rectlWin; + + PRECTL pRectl; + ULONG cRectl; + PBLTRECT pBltRect; + ULONG cBltRect; +} VODATA; + +static BOOL voQueryInfo(PVIDEOOUTPUTINFO pInfo); +static PVODATA voOpen(); +static VOID voClose(PVODATA pVOData); +static BOOL voSetVisibleRegion(PVODATA pVOData, HWND hwnd, + SDL_DisplayMode *pSDLDisplayMode, + HRGN hrgnShape, BOOL fVisible); +static PVOID voVideoBufAlloc(PVODATA pVOData, ULONG ulWidth, ULONG ulHeight, + ULONG ulBPP, ULONG fccColorEncoding, + PULONG pulScanLineSize); +static VOID voVideoBufFree(PVODATA pVOData); +static BOOL voUpdate(PVODATA pVOData, HWND hwnd, SDL_Rect *pSDLRects, + ULONG cSDLRects); + +OS2VIDEOOUTPUT voVMan = { + voQueryInfo, + voOpen, + voClose, + voSetVisibleRegion, + voVideoBufAlloc, + voVideoBufFree, + voUpdate +}; + + +static HMODULE hmodVMan = NULLHANDLE; +static FNVMIENTRY *pfnVMIEntry = NULL; +static ULONG ulVRAMAddress = 0; + +VOID APIENTRY ExitVMan(VOID) +{ + if ( ( ulVRAMAddress != 0 ) && ( hmodVMan != NULLHANDLE ) ) + { + pfnVMIEntry( 0, VMI_CMD_TERMPROC, NULL, NULL ); + DosFreeModule( hmodVMan ); + } + + DosExitList( EXLST_EXIT, (PFNEXITLIST)NULL ); +} + +static BOOL _vmanInit() +{ + ULONG ulRC; + CHAR acBuf[255]; + INITPROCOUT stInitProcOut; + + if ( hmodVMan != NULLHANDLE ) + // Already was initialized. + return TRUE; + + // Load vman.dll + ulRC = DosLoadModule( &acBuf, sizeof(acBuf), "VMAN", &hmodVMan ); + if ( ulRC != NO_ERROR ) + { + debug( "Could not load VMAN.DLL, rc = %u : %s", ulRC, &acBuf ); + hmodVMan = NULLHANDLE; + return FALSE; + } + + // Get VMIEntry. + ulRC = DosQueryProcAddr( hmodVMan, 0L, "VMIEntry", (PFN *)&pfnVMIEntry ); + if ( ulRC != NO_ERROR ) + { + debug( "Could not query address of pfnVMIEntry func. of VMAN.DLL, " + "rc = %u", ulRC ); + DosFreeModule( hmodVMan ); + hmodVMan = NULLHANDLE; + return FALSE; + } + + // VMAN initialization. + stInitProcOut.ulLength = sizeof(stInitProcOut); + ulRC = pfnVMIEntry( 0, VMI_CMD_INITPROC, NULL, &stInitProcOut ); + if ( ulRC != RC_SUCCESS ) + { + debug( "Could not initialize VMAN for this process" ); + pfnVMIEntry = NULL; + DosFreeModule( hmodVMan ); + hmodVMan = NULLHANDLE; + return FALSE; + } + + // Store video memory virtual address. + ulVRAMAddress = stInitProcOut.ulVRAMVirt; + // We use exit list for VMI_CMD_TERMPROC. + if ( DosExitList( EXLST_ADD | 0x00001000, (PFNEXITLIST)ExitVMan ) + != NO_ERROR ) + debug( "DosExitList() failed" ); + + return TRUE; +} + +static PRECTL _getRectlArray(PVODATA pVOData, ULONG cRects) +{ + PRECTL pRectl; + + if ( pVOData->cRectl >= cRects ) + return pVOData->pRectl; + + pRectl = SDL_realloc( pVOData->pRectl, cRects * sizeof(RECTL) ); + if ( pRectl == NULL ) + return NULL; + + pVOData->pRectl = pRectl; + pVOData->cRectl = cRects; + return pRectl; +} + +static PBLTRECT _getBltRectArray(PVODATA pVOData, ULONG cRects) +{ + PBLTRECT pBltRect; + + if ( pVOData->cBltRect >= cRects ) + return pVOData->pBltRect; + + pBltRect = SDL_realloc( pVOData->pBltRect, cRects * sizeof(BLTRECT) ); + if ( pBltRect == NULL ) + return NULL; + + pVOData->pBltRect = pBltRect; + pVOData->cBltRect = cRects; + return pBltRect; +} + + +static BOOL voQueryInfo(PVIDEOOUTPUTINFO pInfo) +{ + ULONG ulRC; + GDDMODEINFO sCurModeInfo; + + if ( !_vmanInit() ) + return FALSE; + + // Query current (desktop) mode. + ulRC = pfnVMIEntry( 0, VMI_CMD_QUERYCURRENTMODE, NULL, &sCurModeInfo ); + if ( ulRC != RC_SUCCESS ) + { + debug( "Could not query desktop video mode." ); + return FALSE; + } + + pInfo->ulBPP = sCurModeInfo.ulBpp; + pInfo->ulHorizResolution = sCurModeInfo.ulHorizResolution; + pInfo->ulVertResolution = sCurModeInfo.ulVertResolution; + pInfo->ulScanLineSize = sCurModeInfo.ulScanLineSize; + pInfo->fccColorEncoding = sCurModeInfo.fccColorEncoding; + + return TRUE; +} + +static PVODATA voOpen() +{ + PVODATA pVOData; + + if ( !_vmanInit() ) + return NULL; + + pVOData = SDL_calloc( 1, sizeof(VODATA) ); + if ( pVOData == NULL ) + { + SDL_OutOfMemory(); + return NULL; + } + + return pVOData; +} + +static VOID voClose(PVODATA pVOData) +{ + if ( pVOData->pRectl != NULL ) + SDL_free( pVOData->pRectl ); + + if ( pVOData->pBltRect != NULL ) + SDL_free( pVOData->pBltRect ); + + voVideoBufFree( pVOData ); +} + +static BOOL voSetVisibleRegion(PVODATA pVOData, HWND hwnd, + SDL_DisplayMode *pSDLDisplayMode, + HRGN hrgnShape, BOOL fVisible) +{ + HPS hps; + BOOL fSuccess = FALSE; + + hps = WinGetPS( hwnd ); + + if ( pVOData->hrgnVisible != NULLHANDLE ) + { + GpiDestroyRegion( hps, pVOData->hrgnVisible ); + pVOData->hrgnVisible = NULLHANDLE; + } + + if ( fVisible ) + { + // Query visible rectangles + + pVOData->hrgnVisible = GpiCreateRegion( hps, 0, NULL ); + if ( pVOData->hrgnVisible == NULLHANDLE ) + { + SDL_SetError( "GpiCreateRegion() failed" ); + } + else + { + if ( WinQueryVisibleRegion( hwnd, pVOData->hrgnVisible ) == RGN_ERROR ) + { + GpiDestroyRegion( hps, pVOData->hrgnVisible ); + pVOData->hrgnVisible = NULLHANDLE; + } + else + { + if ( hrgnShape != NULLHANDLE ) + GpiCombineRegion( hps, pVOData->hrgnVisible, pVOData->hrgnVisible, + hrgnShape, CRGN_AND ); + fSuccess = TRUE; + } + } + + WinQueryWindowRect( hwnd, &pVOData->rectlWin ); + WinMapWindowPoints( hwnd, HWND_DESKTOP, (PPOINTL)&pVOData->rectlWin, 2 ); + + if ( pSDLDisplayMode != NULL ) + { + pVOData->ulScreenHeight = pSDLDisplayMode->h; + pVOData->ulScreenBytesPerLine = + ((PMODEDATA)pSDLDisplayMode->driverdata)->ulScanLineBytes; + } + } + + WinReleasePS( hps ); + + return fSuccess; +} + +static PVOID voVideoBufAlloc(PVODATA pVOData, ULONG ulWidth, ULONG ulHeight, + ULONG ulBPP, ULONG fccColorEncoding, + PULONG pulScanLineSize) +{ + ULONG ulRC; + ULONG ulScanLineSize = ulWidth * (ulBPP >> 3); + + // Destroy previous buffer. + voVideoBufFree( pVOData ); + + if ( ( ulWidth == 0 ) || ( ulHeight == 0 ) || ( ulBPP == 0 ) ) + return NULL; + + // Bytes per line. + ulScanLineSize = ( ulScanLineSize + 3 ) & ~3; /* 4-byte aligning */ + *pulScanLineSize = ulScanLineSize; + + ulRC = DosAllocMem( &pVOData->pBuffer, + (ulHeight * ulScanLineSize) + sizeof(ULONG), + PAG_COMMIT | PAG_EXECUTE | PAG_READ | PAG_WRITE ); + if ( ulRC != NO_ERROR ) + { + debug( "DosAllocMem(), rc = %u", ulRC ); + return NULL; + } + + pVOData->ulBPP = ulBPP; + pVOData->ulScanLineSize = ulScanLineSize; + pVOData->ulWidth = ulWidth; + pVOData->ulHeight = ulHeight; + + return pVOData->pBuffer; +} + +static VOID voVideoBufFree(PVODATA pVOData) +{ + ULONG ulRC; + + if ( pVOData->pBuffer == NULL ) + return; + + ulRC = DosFreeMem( pVOData->pBuffer ); + if ( ulRC != NO_ERROR ) + debug( "DosFreeMem(), rc = %u", ulRC ); + else + pVOData->pBuffer = NULL; +} + +static BOOL voUpdate(PVODATA pVOData, HWND hwnd, SDL_Rect *pSDLRects, + ULONG cSDLRects) +{ + PRECTL prectlDst, prectlScan; + HPS hps; + HRGN hrgnUpdate; + RGNRECT rgnCtl; + SDL_Rect stSDLRectDef; + BMAPINFO bmiSrc; + BMAPINFO bmiDst; + PPOINTL pptlSrcOrg; + PBLTRECT pbrDst; + HWREQIN sHWReqIn; + BITBLTINFO sBitbltInfo = { 0 }; + ULONG ulIdx; +// RECTL rectlScreenUpdate; + + if ( pVOData->pBuffer == NULL ) + return FALSE; + + if ( pVOData->hrgnVisible == NULLHANDLE ) + return TRUE; + + bmiSrc.ulLength = sizeof(BMAPINFO); + bmiSrc.ulType = BMAP_MEMORY; + bmiSrc.ulWidth = pVOData->ulWidth; + bmiSrc.ulHeight = pVOData->ulHeight; + bmiSrc.ulBpp = pVOData->ulBPP; + bmiSrc.ulBytesPerLine = pVOData->ulScanLineSize; + bmiSrc.pBits = (PBYTE)pVOData->pBuffer; + + bmiDst.ulLength = sizeof(BMAPINFO); + bmiDst.ulType = BMAP_VRAM; + bmiDst.pBits = (PBYTE)ulVRAMAddress; + bmiDst.ulWidth = bmiSrc.ulWidth; + bmiDst.ulHeight = bmiSrc.ulHeight; + bmiDst.ulBpp = bmiSrc.ulBpp; + bmiDst.ulBytesPerLine = pVOData->ulScreenBytesPerLine; + + // List of update rectangles. This is the intersection of requested + // rectangles and visible rectangles. + + if ( cSDLRects == 0 ) + { + // Full update requested. + stSDLRectDef.x = 0; + stSDLRectDef.y = 0; + stSDLRectDef.w = bmiSrc.ulWidth; + stSDLRectDef.h = bmiSrc.ulHeight; + pSDLRects = &stSDLRectDef; + cSDLRects = 1; + } + + // Make list of destionation rectangles (prectlDst) list from the source + // list (prectl). + prectlDst = _getRectlArray( pVOData, cSDLRects ); + if ( prectlDst == NULL ) + { + debug( "Not enough memory" ); + return FALSE; + } + prectlScan = prectlDst; + for( ulIdx = 0; ulIdx < cSDLRects; ulIdx++, pSDLRects++, prectlScan++ ) + { + prectlScan->xLeft = pSDLRects->x; + prectlScan->yTop = pVOData->ulHeight - pSDLRects->y; + prectlScan->xRight = prectlScan->xLeft + pSDLRects->w; + prectlScan->yBottom = prectlScan->yTop - pSDLRects->h; + } + + hps = WinGetPS( hwnd ); + if ( hps == NULLHANDLE ) + return FALSE; + + // Make destination region to update. + hrgnUpdate = GpiCreateRegion( hps, cSDLRects, prectlDst ); + // "AND" on visible and destination regions, result is region to update. + GpiCombineRegion( hps, hrgnUpdate, hrgnUpdate, pVOData->hrgnVisible, + CRGN_AND ); + + // Get rectangles of the region to update. + rgnCtl.ircStart = 1; + rgnCtl.crc = 0; + rgnCtl.ulDirection = 1; + rgnCtl.crcReturned = 0; + GpiQueryRegionRects( hps, hrgnUpdate, NULL, &rgnCtl, NULL ); + if ( rgnCtl.crcReturned == 0 ) + { + GpiDestroyRegion( hps, hrgnUpdate ); + WinReleasePS( hps ); + return TRUE; + } + // We don't need prectlDst, use it again to store update regions. + prectlDst = _getRectlArray( pVOData, rgnCtl.crcReturned ); + if ( prectlDst == NULL ) + { + debug( "Not enough memory" ); + GpiDestroyRegion( hps, hrgnUpdate ); + WinReleasePS( hps ); + return FALSE; + } + rgnCtl.ircStart = 1; + rgnCtl.crc = rgnCtl.crcReturned; + rgnCtl.ulDirection = 1; + GpiQueryRegionRects( hps, hrgnUpdate, NULL, &rgnCtl, prectlDst ); + GpiDestroyRegion( hps, hrgnUpdate ); + WinReleasePS( hps ); + cSDLRects = rgnCtl.crcReturned; + // Now cRect/prectlDst is a list of regions in window (update && visible). + + // Make lists for blitting from update regions. + + pbrDst = _getBltRectArray( pVOData, cSDLRects ); + if ( pbrDst == NULL ) + { + debug( "Not enough memory" ); + return FALSE; + } + + prectlScan = prectlDst; + pptlSrcOrg = (PPOINTL)prectlDst; // Yes, this memory block will be used again. + for( ulIdx = 0; ulIdx < cSDLRects; ulIdx++, prectlScan++, pptlSrcOrg++ ) + { + pbrDst[ulIdx].ulXOrg = pVOData->rectlWin.xLeft + prectlScan->xLeft; + pbrDst[ulIdx].ulYOrg = pVOData->ulScreenHeight - + ( pVOData->rectlWin.yBottom + prectlScan->yTop ); + pbrDst[ulIdx].ulXExt = prectlScan->xRight - prectlScan->xLeft; + pbrDst[ulIdx].ulYExt = prectlScan->yTop - prectlScan->yBottom; + pptlSrcOrg->x = prectlScan->xLeft; + pptlSrcOrg->y = bmiSrc.ulHeight - prectlScan->yTop; + } + pptlSrcOrg = (PPOINTL)prectlDst; + + // Request HW + sHWReqIn.ulLength = sizeof(HWREQIN); + sHWReqIn.ulFlags = REQUEST_HW; + sHWReqIn.cScrChangeRects = 1; + sHWReqIn.arectlScreen = &pVOData->rectlWin; + if ( pfnVMIEntry( 0, VMI_CMD_REQUESTHW, &sHWReqIn, NULL ) != RC_SUCCESS ) + { + debug( "pfnVMIEntry(,VMI_CMD_REQUESTHW,,) failed" ); + sHWReqIn.cScrChangeRects = 0; // for fail signal only. + } + else + { + RECTL rclSrcBounds; + + rclSrcBounds.xLeft = 0; + rclSrcBounds.yBottom = 0; + rclSrcBounds.xRight = bmiSrc.ulWidth; + rclSrcBounds.yTop = bmiSrc.ulHeight; + + sBitbltInfo.ulLength = sizeof(BITBLTINFO); + sBitbltInfo.ulBltFlags = BF_DEFAULT_STATE | BF_ROP_INCL_SRC | BF_PAT_HOLLOW; + sBitbltInfo.cBlits = cSDLRects; + sBitbltInfo.ulROP = ROP_SRCCOPY; + sBitbltInfo.pSrcBmapInfo = &bmiSrc; + sBitbltInfo.pDstBmapInfo = &bmiDst; + sBitbltInfo.prclSrcBounds = &rclSrcBounds; + sBitbltInfo.prclDstBounds = &pVOData->rectlWin; + sBitbltInfo.aptlSrcOrg = pptlSrcOrg; + sBitbltInfo.abrDst = pbrDst; + + // Screen update. + if ( pfnVMIEntry( 0, VMI_CMD_BITBLT, &sBitbltInfo, NULL ) != RC_SUCCESS ) + { + debug( "pfnVMIEntry(,VMI_CMD_BITBLT,,) failed" ); + sHWReqIn.cScrChangeRects = 0; // for fail signal only. + } + + // Release HW. + sHWReqIn.ulFlags = 0; + if ( pfnVMIEntry( 0, VMI_CMD_REQUESTHW, &sHWReqIn, NULL ) != RC_SUCCESS ) + debug( "pfnVMIEntry(,VMI_CMD_REQUESTHW,,) failed" ); + } + + return sHWReqIn.cScrChangeRects != 0; +} diff --git a/test/testnativeos2.c b/test/testnativeos2.c new file mode 100644 index 000000000..29b491624 --- /dev/null +++ b/test/testnativeos2.c @@ -0,0 +1,59 @@ +/* + Copyright (C) 1997-2016 Sam Lantinga + + 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. +*/ + +#include "testnative.h" + +#ifdef TEST_NATIVE_OS2 + +#define WIN_CLIENT_CLASS "SDL Test" + +static void *CreateWindowNative(int w, int h); +static void DestroyWindowNative(void *window); + +NativeWindowFactory OS2WindowFactory = { + "OS/2", + CreateWindowNative, + DestroyWindowNative +}; + +static void *CreateWindowNative(int w, int h) +{ + HWND hwnd; + HWND hwndFrame; + ULONG ulFrameFlags = FCF_TASKLIST | FCF_DLGBORDER | FCF_TITLEBAR | + FCF_SYSMENU | FCF_SHELLPOSITION | + FCF_SIZEBORDER | FCF_MINBUTTON | FCF_MAXBUTTON; + + WinRegisterClass( 0, WIN_CLIENT_CLASS, WinDefWindowProc, + CS_SIZEREDRAW | CS_MOVENOTIFY, + sizeof(ULONG) ); // We should have minimum 4 bytes. + + hwndFrame = WinCreateStdWindow( HWND_DESKTOP, 0, &ulFrameFlags, + WIN_CLIENT_CLASS, "SDL Test", 0, 0, 1, &hwnd ); + if ( hwndFrame == NULLHANDLE ) + { + return 0; + } + + WinSetWindowPos( hwndFrame, HWND_TOP, 0, 0, w, h, + SWP_ZORDER | SWP_ACTIVATE | SWP_SIZE | SWP_SHOW ); + + return (void *)hwndFrame; // We may returns client or frame window handle + // for SDL_CreateWindowFrom(). +} + +static void DestroyWindowNative(void *window) +{ + WinDestroyWindow( (HWND)window ); +} + +#endif /* TEST_NATIVE_OS2 */