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.
diff --git a/src/audio/os2/SDL_os2audio.c b/src/audio/os2/SDL_os2audio.c
new file mode 100644
index 0000000..786deb1
--- /dev/null
+++ b/src/audio/os2/SDL_os2audio.c
@@ -0,0 +1,472 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_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 0000000..014e35e
--- /dev/null
+++ b/src/audio/os2/SDL_os2audio.h
@@ -0,0 +1,53 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#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 <os2.h>
+#include <os2me.h>
+
+/* 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 0000000..d42e668
--- /dev/null
+++ b/src/core/os2/SDL_os2.c
@@ -0,0 +1,36 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if 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 0000000..a455c49
--- /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 0000000..b82e903
--- /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 <os2.h>
+#include <iconv.h>
+
+//#define DEBUG
+
+#ifdef DEBUG
+# include <stdio.h>
+# 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 0000000..e22ce64
--- /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 <iconv.h>
+
+#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 0000000..b336dab
--- /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 <stddef.h> /* size_t */
+#include <errno.h>
+
+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 0000000..7dffd30
--- /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 0000000..dd9e83a
--- /dev/null
+++ b/src/core/os2/geniconv/os2cp.c
@@ -0,0 +1,383 @@
+#include "os2cp.h"
+#define INCL_DOSNLS
+#define INCL_DOSERRORS
+#include <os2.h>
+#include <string.h>
+#include <ctype.h>
+
+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 0000000..542b41e
--- /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 0000000..1e2ba24
--- /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 <uconv.h>
+#include <stdlib.h>
+#include <string.h>
+#ifdef ICONV_THREAD_SAFE
+#define INCL_DOSSEMAPHORES
+#define INCL_DOSERRORS
+#include <os2.h>
+#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 0000000..51ce4a1
--- /dev/null
+++ b/src/core/os2/geniconv/sys2utf8.c
@@ -0,0 +1,97 @@
+#include <iconv.h>
+#include <stdlib.h>
+
+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 0000000..efd0b95
--- /dev/null
+++ b/src/core/os2/geniconv/test.c
@@ -0,0 +1,45 @@
+#include <stdio.h>
+#include <string.h>
+#include <geniconv.h>
+
+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 0000000..2420ae2
--- /dev/null
+++ b/src/filesystem/os2/SDL_sysfilesystem.c
@@ -0,0 +1,122 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#ifdef SDL_FILESYSTEM_OS2
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* System dependent filesystem routines */
+
+#include "SDL_error.h"
+#include "SDL_filesystem.h"
+#include "../../core/os2/SDL_os2.h"
+
+#include <sys/types.h>
+#include <direct.h>
+#define INCL_DOSPROCESS
+#define INCL_DOSERRORS
+#include <os2.h>
+
+
+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 0000000..7d08f94
--- /dev/null
+++ b/src/loadso/os2/SDL_sysloadso.c
@@ -0,0 +1,79 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#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 <os2.h>
+
+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 0000000..40d094d
--- /dev/null
+++ b/src/thread/os2/SDL_sysmutex.c
@@ -0,0 +1,132 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_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 <os2.h>
+
+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 0000000..688b6c6
--- /dev/null
+++ b/src/thread/os2/SDL_syssem.c
@@ -0,0 +1,196 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_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 <os2.h>
+
+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 0000000..15453f7
--- /dev/null
+++ b/src/thread/os2/SDL_systhread.c
@@ -0,0 +1,187 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_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 <os2.h>
+
+#ifndef SDL_PASSED_BEGINTHREAD_ENDTHREAD
+/* We'll use the C library from this DLL */
+#include <process.h>
+
+/* 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 0000000..ba16277
--- /dev/null
+++ b/src/thread/os2/SDL_systhread_c.h
@@ -0,0 +1,25 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+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 0000000..023a241
--- /dev/null
+++ b/src/thread/os2/SDL_systls.c
@@ -0,0 +1,89 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "../../SDL_internal.h"
+
+#if SDL_THREAD_OS2
+
+#include "../../core/os2/SDL_os2.h"
+
+#include "SDL_thread.h"
+#include "../SDL_thread_c.h"
+
+#define INCL_DOSPROCESS
+#define INCL_DOSERRORS
+#include <os2.h>
+
+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 0000000..7c63e90
--- /dev/null
+++ b/src/thread/os2/SDL_systls_c.h
@@ -0,0 +1,38 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#include "../../SDL_internal.h"
+
+#if SDL_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 0000000..aa4ac93
--- /dev/null
+++ b/src/timer/os2/SDL_systimer.c
@@ -0,0 +1,189 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_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 <os2.h>
+
+// 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 0000000..d4f4982
--- /dev/null
+++ b/src/video/os2/SDL_os2dive.c
@@ -0,0 +1,348 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+#include "../SDL_sysvideo.h"
+#define INCL_WIN
+#define INCL_GPI
+#include <os2.h>
+#define _MEERROR_H_
+#include <mmioos2.h>
+#include <os2me.h>
+#define INCL_MM_OS2
+#include <dive.h>
+#include <fourcc.h>
+#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 0000000..9361199
--- /dev/null
+++ b/src/video/os2/SDL_os2messagebox.c
@@ -0,0 +1,593 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_OS2
+
+/* Display a OS/2 message box */
+
+#include "SDL.h"
+#include "../../core/os2/SDL_os2.h"
+#include "SDL_os2video.h"
+#define INCL_WIN
+#include <os2.h>
+
+#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 0000000..bd2fdf7
--- /dev/null
+++ b/src/video/os2/SDL_os2messagebox.h
@@ -0,0 +1,29 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_OS2
+
+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 0000000..67d3f1c
--- /dev/null
+++ b/src/video/os2/SDL_os2mouse.c
@@ -0,0 +1,204 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_OS2
+
+#include "SDL_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 0000000..82189a8
--- /dev/null
+++ b/src/video/os2/SDL_os2mouse.h
@@ -0,0 +1,33 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#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 0000000..0e90c4f
--- /dev/null
+++ b/src/video/os2/SDL_os2output.h
@@ -0,0 +1,54 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#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 0000000..d5429f5
--- /dev/null
+++ b/src/video/os2/SDL_os2util.c
@@ -0,0 +1,118 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_OS2
+
+#include "SDL_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 0000000..6aac3fd
--- /dev/null
+++ b/src/video/os2/SDL_os2util.h
@@ -0,0 +1,38 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+
+#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 <os2.h>
+
+/*#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 0000000..c6f5b7a
--- /dev/null
+++ b/src/video/os2/SDL_os2video.c
@@ -0,0 +1,1786 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#if SDL_VIDEO_DRIVER_OS2
+
+#include "SDL_video.h"
+#include "SDL_mouse.h"
+#include "../SDL_pixels_c.h"
+#include "../SDL_shape_internals.h"
+#include "../../events/SDL_events_c.h"
+#include "SDL_os2video.h"
+#include "SDL_syswm.h"
+#include "SDL_os2util.h"
+#define _MEERROR_H_
+#include <mmioos2.h>
+#include <fourcc.h>
+
+#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 0000000..633efa2
--- /dev/null
+++ b/src/video/os2/SDL_os2video.h
@@ -0,0 +1,83 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+
+#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 <os2.h>
+//#include <gradd.h> // 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 0000000..394c695
--- /dev/null
+++ b/src/video/os2/SDL_os2vman.c
@@ -0,0 +1,512 @@
+/*
+ Simple DirectMedia Layer
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+*/
+#include "../../SDL_internal.h"
+#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 <os2.h>
+#define INCL_GRE_DEVICE
+#define INCL_GRE_DEVMISC
+#include <pmddi.h>
+#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 0000000..29b4916
--- /dev/null
+++ b/test/testnativeos2.c
@@ -0,0 +1,59 @@
+/*
+ Copyright (C) 1997-2016 Sam Lantinga <slouken@libsdl.org>
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely.
+*/
+
+#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 */