Commit b08452cb authored by Ryan C. Gordon's avatar Ryan C. Gordon

OS/2 port!

This was mostly, if not entirely, written by "Doodle" and "Caetano":
    doodle@scenergy.dfmk.hu
    daniel@caetano.eng.br

--ryan.

--HG--
extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/trunk%401193
parent c154edb9
===========
SDL on OS/2
===========
Last updated on Oct 02, 2005.
1. How to compile?
------------------
To compile this, you'll need the followings installed:
- The OS/2 Developer's Toolkit
- The OpenWatcom compiler
(http://www.openwatcom.org)
- The FSLib library
(ftp://ftp.netlabs.org/pub/SDL)
Please edit the second, fourth and fifth lines of setvars.cmd file
to set the folders where the toolkit, the OW compiler and the FSLib are.
You won't need NASM yet (The Netwide Assembler), you can leave that line.
Run setvars.cmd, and you should get a shell in which you can
compile SDL.
Check the "Watcom.mif" file. This is the file which is included by all the
Watcom makefiles, so changes here will affect the whole build process.
There is a line in there which determines if the resulting SDL.DLL will be
a 'debug' or a 'release' build. The 'debug' version is full of printf()'s,
so if something goes wrong, its output can help a lot for debugging.
Then go to the 'src' folder, and run "wmake -f makefile.wat".
This should create the SDL.DLL and the corresponding SDL.LIB file there.
To test applications, it's a good idea to use the 'debug' build of SDL, and
redirect the standard output and standard error output to files, to see what
happens internally in SDL.
(like: testsprite >stdout.txt 2>stderr.txt)
To rebuild SDL, use the following commands in 'src' folder:
wmake -f makefile.wat clean
wmake -f makefile.wat
2. How to compile the testapps?
-------------------------------
Once you have SDL.DLL compiled, navigate into the 'test' folder, copy in there
the newly built SDL.DLL, and copy in there FSLib.DLL.
Then run "wmake -f makefile.wat" in there to compile some of the testapps.
3. What is missing?
-------------------
The following things are missing from this SDL implementation:
- MMX, SSE and 3DNOW! optimized video blitters?
- HW Video surfaces
- OpenGL support
4. Special Keys / Full-Screen support
-------------------------------------
There are two special hot-keys implemented:
- Alt+Home switches between fullscreen and windowed mode
- Alt+End simulates closing the window (can be used as a Panic key)
Only the LEFT Alt key will work.
5. Joysticks on SDL/2
---------------------
The Joystick detection only works for standard joysticks (2 buttons, 2 axes
and the like). Therefore, if you use a non-standard joystick, you should
specify its features in the SDL_OS2_JOYSTICK environment variable in a batch
file or CONFIG.SYS, so SDL applications can provide full capability to your
device. The syntax is:
SET SDL_OS2_JOYSTICK=[JOYSTICK_NAME] [AXES] [BUTTONS] [HATS] [BALLS]
So, it you have a Gravis GamePad with 4 axes, 2 buttons, 2 hats and 0 balls,
the line should be:
SET SDL_OS2_JOYSTICK=Gravis_GamePad 4 2 2 0
If you want to add spaces in your joystick name, just surround it with
quotes or double-quotes:
SET SDL_OS2_JOYSTICK='Gravis GamePad' 4 2 2 0
or
SET SDL_OS2_JOYSTICK="Gravis GamePad" 4 2 2 0
Notive However that Balls and Hats are not supported under OS/2, and the
value will be ignored... but it is wise to define these correctly because
in the future those can be supported.
Also the number of buttons is limited to 2 when using two joysticks,
4 when using one joystick with 4 axes, 6 when using a joystick with 3 axes
and 8 when using a joystick with 2 axes. Notice however these are limitations
of the Joystick Port hardware, not OS/2.
6. Next steps...
----------------
Things to do:
- Implement missing stuffs (look for 'TODO' string in source code!)
- Finish video driver (the 'wincommon' can be a good example for missing
things like application icon and so on...)
- Enable MMX/SSE/SSE2 acceleration functions
- Rewrite CDROM support using DOS Ioctl for better support.
7. Contacts
-----------
You can contact the developers for bugs:
Area Developer email
General (Audio/Video/System) Doodle doodle@scenergy.dfmk.hu
CDROM and Joystick Caetano daniel@caetano.eng.br
Notice however that SDL/2 is 'in development' stage so ... if you want to help,
please, be our guest and contact us!
#=============================================================================
# This file contains the common includes for the
# Watcom makefiles to build SDL.DLL for OS/2
#
#
#=============================================================================
# Create debug build or not?
#debug_build=defined
# Special flags for building SDL
SDLCFlags = -dBUILD_SDL -dCHECK_LEAKS
#
#==============================================================================
#
!ifdef debug_build
debugflags = -d2 -dDEBUG_BUILD
!else
debugflags =
!endif
cflags = -zq $(debugflags) -bd -bm -bt=OS2 -5s -fpi -sg -otexan -wx -ei $(SDLCFlags) $(ExtraCFlags)
.extensions:
.extensions: .lib .dll .obj .c .asm
.c.obj : .AUTODEPEND
wcc386 $[* $(cflags)
.asm.obj : .AUTODEPEND
nasm -t -O2 -f obj -I$(%include) $[*.asm
......@@ -55,9 +55,8 @@ static char rcsid =
(defined(__arm__) || defined(__thumb__)) || \
(defined(__sh__) || defined(__sh64__)) || \
(defined(__mips__) && defined(__MIPSEL__)) || \
defined(__SYMBIAN32__) || \
defined(__x86_64__) || \
defined(__LITTLE_ENDIAN__)
defined(__SYMBIAN32__) || defined(__x86_64__) || \
defined(__OS2__) || defined(__LITTLE_ENDIAN__)
#define SDL_BYTEORDER SDL_LIL_ENDIAN
#else
#define SDL_BYTEORDER SDL_BIG_ENDIAN
......
......@@ -50,7 +50,50 @@ struct SDL_Thread;
typedef struct SDL_Thread SDL_Thread;
/* Create a thread */
#ifdef __OS2__
/*
We compile SDL into a DLL on OS/2. This means, that it's the DLL which
creates a new thread for the calling process with the SDL_CreateThread()
API. There is a problem with this, that only the RTL of the SDL.DLL will
be initialized for those threads, and not the RTL of the calling application!
To solve this, we make a little hack here.
We'll always use the caller's _beginthread() and _endthread() APIs to
start a new thread. This way, it it's the SDL.DLL which uses this API,
then the RTL of SDL.DLL will be used to create the new thread, and if it's
the application, then the RTL of the application will be used.
So, in short:
Always use the _beginthread() and _endthread() of the calling runtime library!
*/
#ifdef __WATCOMC__
#include <process.h> // This has _beginthread() and _endthread() defined!
#endif
#ifdef __EMX__
#include <stdlib.h> // This has _beginthread() and _endthread() defined, if -Zmt flag is used!
#endif
typedef Uint32 SDLCALL (*pfnSDL_CurrentBeginThread)(void (*pfnThreadFn)(void *), Uint32 uiStackSize, void *pParam);
typedef void SDLCALL (*pfnSDL_CurrentEndThread)(void);
extern DECLSPEC SDL_Thread * SDLCALL SDL_CreateThread_Core(int (*fn)(void *), void *data, pfnSDL_CurrentBeginThread pfnBeginThread, pfnSDL_CurrentEndThread pfnEndThread);
// Disable warnings about unreferenced symbol!
#pragma disable_message (202)
static Uint32 SDLCALL SDL_CurrentBeginThread(void (*pfnThreadFn)(void *), Uint32 uiStackSize, void *pParam)
{
return _beginthread(pfnThreadFn, NULL, uiStackSize, pParam);
}
static void SDLCALL SDL_CurrentEndThread(void)
{
_endthread();
}
#define SDL_CreateThread(fn, data) SDL_CreateThread_Core(fn, data, SDL_CurrentBeginThread, SDL_CurrentEndThread)
#else
extern DECLSPEC SDL_Thread * SDLCALL SDL_CreateThread(int (SDLCALL *fn)(void *), void *data);
#endif
/* Get the 32-bit thread identifier for the current thread */
extern DECLSPEC Uint32 SDLCALL SDL_ThreadID(void);
......
......@@ -57,7 +57,7 @@ typedef signed int Sint32;
#if !defined(__STRICT_ANSI__)
#ifdef __osf__ /* Tru64 */
#define SDL_HAS_64BIT_TYPE long
#elif defined(__GNUC__) || defined(__MWERKS__) || defined(__SUNPRO_C) || defined(__DECC)
#elif defined(__GNUC__) || defined(__MWERKS__) || defined(__SUNPRO_C) || defined(__DECC) || defined(__WATCOMC__)
#define SDL_HAS_64BIT_TYPE long long
#elif defined(_MSC_VER) /* VC++ */
#define SDL_HAS_64BIT_TYPE __int64
......
......@@ -56,9 +56,21 @@
# define DECLSPEC __declspec(dllexport)
# endif
# else
# ifdef __OS2__
# ifdef __WATCOMC__
# ifdef BUILD_SDL
# define DECLSPEC __declspec(dllexport)
# else
# define DECLSPEC
# endif
# else
# define DECLSPEC
# endif
# else
# define DECLSPEC
# endif
# endif
# endif
#endif
/* By default SDL uses the C calling convention */
......@@ -66,8 +78,14 @@
#if defined(WIN32) && !defined(__GNUC__)
#define SDLCALL __cdecl
#else
#ifdef __OS2__
/* But on OS/2, we use the _System calling convention */
/* to be compatible with every compiler */
#define SDLCALL _System
#else
#define SDLCALL
#endif
#endif
#endif /* SDLCALL */
/* Removed DECLSPEC on Symbian OS because SDL cannot be a DLL in EPOC */
......
@ECHO OFF
SET WATCOM=d:\watcom
SET NASM=d:\nasm
SET OS2TK=d:\os2tk45
SET FSLIB=d:\watcom\projects\FSLib
SET PATH=%WATCOM%\BINP;%WATCOM%\BINW;%os2tk%\bin;%NASM%;%PATH%
SET INCLUDE=%WATCOM%\H;%WATCOM%\H\OS2
SET FINCLUDE=%WATCOM%\SRC\FORTRAN
SET EDPATH=%WATCOM%\EDDAT
SET HELP=%WATCOM%\BINP\HELP;%HELP%
SET BOOKSHELF=%WATCOM%\BINP\HELP;%BOOKSHELF%
SET BEGINLIBPATH=%WATCOM%\BINP\DLL
cmd
#=============================================================================
# This is a Watcom makefile to build SDL.DLL for OS/2
#
#
#=============================================================================
dllname=SDL
audioobjs = audio\SDL_audio.obj audio\SDL_audiocvt.obj audio\SDL_audiomem.obj &
audio\SDL_mixer.obj audio\SDL_mixer_MMX_VC.obj audio\SDL_wave.obj &
audio\SDL_dart.obj
cdromobjs = cdrom\SDL_cdrom.obj cdrom\SDL_syscdrom.obj
cpuinfoobjs = cpuinfo\SDL_cpuinfo.obj
endianobjs = endian\SDL_endian.obj
eventsobjs = events\SDL_active.obj events\SDL_events.obj events\SDL_expose.obj &
events\SDL_keyboard.obj events\SDL_mouse.obj events\SDL_quit.obj &
events\SDL_resize.obj
fileobjs = file\SDL_rwops.obj
hermesobjs = hermes\mmx_main.obj hermes\mmxp2_32.obj hermes\x86_main.obj &
hermes\x86p_16.obj hermes\x86p_32.obj
joystickobjs = joystick\SDL_joystick.obj joystick\SDL_sysjoystick.obj
threadobjs = thread\SDL_thread.obj thread\SDL_sysmutex.obj &
thread\SDL_syssem.obj thread\SDL_systhread.obj &
thread\SDL_syscond.obj
timerobjs = timer\SDL_timer.obj timer\SDL_systimer.obj
videoobjs = video\SDL_blit.obj video\SDL_blit_0.obj video\SDL_blit_1.obj &
video\SDL_blit_A.obj video\SDL_blit_N.obj video\SDL_bmp.obj &
video\SDL_cursor.obj video\SDL_gamma.obj video\SDL_pixels.obj &
video\SDL_RLEaccel.obj video\SDL_stretch.obj video\SDL_surface.obj &
video\SDL_video.obj video\SDL_yuv.obj video\SDL_yuv_mmx.obj &
video\SDL_yuv_sw.obj video\SDL_os2fslib.obj
object_files= SDL.obj SDL_error.obj SDL_fatal.obj SDL_getenv.obj &
SDL_loadso.obj $(audioobjs) $(cpuinfoobjs) $(endianobjs) &
$(eventsobjs) $(fileobjs) $(joystickobjs) &
$(threadobjs) $(timerobjs) $(videoobjs) $(cdromobjs)
# Extra stuffs to pass to C compiler:
ExtraCFlags=
#
#==============================================================================
#
!include ..\Watcom.mif
.before
@set include=$(%os2tk)\h;$(%include);../include;./thread;./thread/os2;./video;./cdrom;./cdrom/os2;./joystick;./joystick/os2;
all : check_subdir_objects $(dllname).dll $(dllname).lib
$(dllname).dll : $(dllname).lnk $(object_files)
wlink @$(dllname)
check_subdir_objects: .always .symbolic
@cd audio
@wmake -h -f Makefile.wat
@cd ..\cdrom
@wmake -h -f Makefile.wat
@cd ..\cpuinfo
@wmake -h -f Makefile.wat
@cd ..\endian
@wmake -h -f Makefile.wat
@cd ..\events
@wmake -h -f Makefile.wat
@cd ..\file
@wmake -h -f Makefile.wat
@cd ..\joystick
@wmake -h -f Makefile.wat
@cd ..\thread
@wmake -h -f Makefile.wat
@cd ..\timer
@wmake -h -f Makefile.wat
@cd ..\video
@wmake -h -f Makefile.wat
@cd ..
$(dllname).lnk :
@echo Creating linker file ($(dllname).lnk)...
@echo $#============================================================================= >$^@
@echo $# This is a linker file to build SDL.DLL for OS/2 >>$^@
@echo $# >>$^@
@echo $# Generated automatically by Makefile.wat >>$^@
@echo $#============================================================================= >>$^@
@echo SYSTEM 386 LX DLL INITINSTANCE TERMINSTANCE >>$^@
@echo NAME $^& >>$^@
@for %i in ($(object_files)) do @echo FILE %i >>$^@
@echo LIBPATH %os2tk%\lib >>$^@
@echo LIBPATH %fslib% >>$^@
@echo LIB mmpm2.lib >>$^@
@echo LIB fslib.lib >>$^@
@echo OPTION QUIET >>$^@
@echo OPTION MAP=$^&.map >>$^@
@echo OPTION DESCRIPTION 'Simple DirectMedia Layer v1.2.7' >>$^@
@echo OPTION ELIMINATE >>$^@
@echo OPTION MANYAUTODATA >>$^@
@echo OPTION OSNAME='OS/2 and eComStation' >>$^@
@echo OPTION SHOWDEAD >>$^@
@echo Linker file created!
$(dllname).lib : $(dllname).dll
implib $(dllname).lib $(dllname).dll
clean : .SYMBOLIC
@if exist *.dll del *.dll
@if exist *.lib del *.lib
@if exist *.obj del *.obj
@if exist *.lnk del *.lnk
@if exist *.map del *.map
@if exist *.res del *.res
@if exist *.lst del *.lst
@cd audio
@wmake -h -f Makefile.wat clean
@cd ..\cdrom
@wmake -h -f Makefile.wat clean
@cd ..\cpuinfo
@wmake -h -f Makefile.wat clean
@cd ..\endian
@wmake -h -f Makefile.wat clean
@cd ..\events
@wmake -h -f Makefile.wat clean
@cd ..\file
@wmake -h -f Makefile.wat clean
@cd ..\joystick
@wmake -h -f Makefile.wat clean
@cd ..\thread
@wmake -h -f Makefile.wat clean
@cd ..\timer
@wmake -h -f Makefile.wat clean
@cd ..\video
@wmake -h -f Makefile.wat clean
@cd ..
......@@ -220,15 +220,25 @@ Uint32 SDL_WasInit(Uint32 flags)
void SDL_Quit(void)
{
/* Quit all subsystems */
#ifdef DEBUG_BUILD
printf("[SDL_Quit] : Enter! Calling QuitSubSystem()\n"); fflush(stdout);
#endif
SDL_QuitSubSystem(SDL_INIT_EVERYTHING);
#ifdef CHECK_LEAKS
#ifdef DEBUG_BUILD
printf("[SDL_Quit] : CHECK_LEAKS\n"); fflush(stdout);
#endif
/* Print the number of surfaces not freed */
if ( surfaces_allocated != 0 ) {
fprintf(stderr, "SDL Warning: %d SDL surfaces extant\n",
surfaces_allocated);
}
#endif
#ifdef DEBUG_BUILD
printf("[SDL_Quit] : SDL_UninstallParachute()\n"); fflush(stdout);
#endif
/* Uninstall any parachute signal handlers */
SDL_UninstallParachute();
......@@ -236,6 +246,10 @@ void SDL_Quit(void)
#if !defined(DISABLE_THREADS) && defined(ENABLE_PTH)
pth_kill();
#endif
#ifdef DEBUG_BUILD
printf("[SDL_Quit] : Returning!\n"); fflush(stdout);
#endif
}
/* Return the library version number */
......@@ -244,6 +258,7 @@ const SDL_version * SDL_Linked_Version(void)
return(&version);
}
#ifndef __OS2__
#if defined(_WIN32_WCE) || (defined(__WATCOMC__) && defined(BUILD_DLL))
/* Need to include DllMain() on Windows CE and Watcom C for some reason.. */
#include <windows.h>
......@@ -262,3 +277,75 @@ BOOL APIENTRY DllMain( HANDLE hModule,
return TRUE;
}
#endif /* _WIN32_WCE and building DLL with Watcom C */
#else
// Building for OS/2
#ifdef __WATCOMC__
#define INCL_DOSERRORS
#define INCL_DOSEXCEPTIONS
#include <os2.h>
// Exception handler to prevent the Audio thread hanging, making a zombie process!
ULONG _System SDL_Main_ExceptionHandler(PEXCEPTIONREPORTRECORD pERepRec,
PEXCEPTIONREGISTRATIONRECORD pERegRec,
PCONTEXTRECORD pCtxRec,
PVOID p)
{
if (pERepRec->fHandlerFlags & EH_EXIT_UNWIND)
return XCPT_CONTINUE_SEARCH;
if (pERepRec->fHandlerFlags & EH_UNWINDING)
return XCPT_CONTINUE_SEARCH;
if (pERepRec->fHandlerFlags & EH_NESTED_CALL)
return XCPT_CONTINUE_SEARCH;
// Do cleanup at every fatal exception!
if (((pERepRec->ExceptionNum & XCPT_SEVERITY_CODE) == XCPT_FATAL_EXCEPTION) &&
(pERepRec->ExceptionNum != XCPT_BREAKPOINT) &&
(pERepRec->ExceptionNum != XCPT_SINGLE_STEP)
)
{
if (SDL_initialized & SDL_INIT_AUDIO)
{
// This removes the zombie audio thread in case of emergency.
#ifdef DEBUG_BUILD
printf("[SDL_Main_ExceptionHandler] : Calling SDL_CloseAudio()!\n");
#endif
SDL_CloseAudio();
}
}
return (XCPT_CONTINUE_SEARCH);
}
EXCEPTIONREGISTRATIONRECORD SDL_Main_xcpthand = {0, SDL_Main_ExceptionHandler};
// The main DLL entry for DLL Initialization and Uninitialization:
unsigned _System LibMain(unsigned hmod, unsigned termination)
{
if (termination)
{
#ifdef DEBUG_BUILD
// printf("[SDL DLL Unintialization] : Removing exception handler\n");
#endif
DosUnsetExceptionHandler(&SDL_Main_xcpthand);
return 1;
} else
{
#ifdef DEBUG_BUILD
// Make stdout and stderr unbuffered!
setbuf(stdout, NULL);
setbuf(stderr, NULL);
#endif
// Fire up exception handler
#ifdef DEBUG_BUILD
// printf("[SDL DLL Initialization] : Setting exception handler\n");
#endif
// Set exception handler
DosSetExceptionHandler(&SDL_Main_xcpthand);
return 1;
}
}
#endif
#endif
......@@ -44,6 +44,8 @@ static char rcsid =
# include "loadso/beos/SDL_loadso.c"
#elif defined(__MINT__) && defined(ENABLE_LDG)
# include "loadso/mint/SDL_loadso.c"
#elif defined(__OS2__)
# include "loadso/os2/SDL_loadso.c"
#else
# include "loadso/dummy/SDL_loadso.c"
#endif /* system type */
......
#=============================================================================
# This is a Watcom makefile to build SDL.DLL for OS/2
#
# Makefile for DART (audio support)
#=============================================================================
object_files= SDL_audio.obj SDL_audiocvt.obj SDL_audiomem.obj SDL_mixer.obj SDL_mixer_MMX_VC.obj SDL_wave.obj SDL_dart.obj
ExtraCFlags=-dUSE_ASM_MIXER_VC -dUSE_DOSSETPRIORITY
#
#==============================================================================
#
!include ..\..\Watcom.mif
.before
set include=$(%os2tk)\h;$(%include);../../include;./dart
all : $(object_files)
SDL_dart.obj: .AUTODEPEND
wcc386 dart\SDL_dart.c $(cflags)
clean : .SYMBOLIC
@if exist *.obj del *.obj
@if exist *.map del *.map
@if exist *.res del *.res
@if exist *.lst del *.lst
......@@ -38,6 +38,12 @@ static char rcsid =
#include "SDL_audiomem.h"
#include "SDL_sysaudio.h"
#ifdef __OS2__
// We'll need the DosSetPriority() API!
#define INCL_DOSPROCESS
#include <os2.h>
#endif
/* Available audio drivers */
static AudioBootStrap *bootstrap[] = {
#ifdef OPENBSD_AUDIO_SUPPORT
......@@ -107,6 +113,9 @@ static AudioBootStrap *bootstrap[] = {
#endif
#ifdef DRENDERER_SUPPORT
&DRENDERER_bootstrap,
#endif
#ifdef __OS2__
&DART_bootstrap,
#endif
NULL
};
......@@ -181,6 +190,16 @@ int SDL_RunAudio(void *audiop)
D(bug("Entering audio loop...\n"));
#endif
#ifdef __OS2__
// Increase the priority of this thread to make sure that
// the audio will be continuous all the time!
#ifdef USE_DOSSETPRIORITY
#ifdef DEBUG_BUILD
printf("[SDL_RunAudio] : Setting priority to ForegroundServer+0! (TID%d)\n", SDL_ThreadID());
#endif
DosSetPriority(PRTYS_THREAD, PRTYC_FOREGROUNDSERVER, 0, 0);
#endif
#endif
/* Loop, filling the audio buffers */
while ( audio->enabled ) {
......@@ -248,6 +267,11 @@ int SDL_RunAudio(void *audiop)
D(bug("CloseAudio..Done, subtask exiting...\n"));
audio_configured = 0;
#endif
#ifdef __OS2__
#ifdef DEBUG_BUILD
printf("[SDL_RunAudio] : Task exiting. (TID%d)\n", SDL_ThreadID());
#endif
#endif
return(0);
}
......
......@@ -12,8 +12,10 @@
// Mixing for 16 bit signed buffers
////////////////////////////////////////////////
#ifndef __WATCOMC__
#include <windows.h>
#include <stdio.h>
#endif
void SDL_MixAudio_MMX_S16_VC(char* dst,char* src,unsigned int nSize,int volume)
{
......@@ -41,7 +43,9 @@ void SDL_MixAudio_MMX_S16_VC(char* dst,char* src,unsigned int nSize,int volume)
psllq mm0, 16 //$16,%%mm0
por mm0, mm1 //%%mm1,%%mm0 // mm0 = vol|vol|vol|vol
#ifndef __WATCOMC__
align 16
#endif
mixloopS16:
movq mm1, [esi] //(%%esi),%%mm1\n" // mm1 = a|b|c|d
movq mm2, mm1 //%%mm1,%%mm2\n" // mm2 = a|b|c|d
......@@ -121,7 +125,9 @@ void SDL_MixAudio_MMX_S8_VC(char* dst,char* src,unsigned int nSize,int volume)
cmp ebx, 0 //$0,%%ebx
je endS8
#ifndef __WATCOMC__
align 16
#endif
mixloopS8:
pxor mm2, mm2 //%%mm2,%%mm2 // mm2 = 0
movq mm1, [esi] //(%%esi),%%mm1 // mm1 = a|b|c|d|e|f|g|h
......
......@@ -172,6 +172,9 @@ extern AudioBootStrap DRENDERER_bootstrap;
#ifdef MMEAUDIO_SUPPORT
extern AudioBootStrap MMEAUDIO_bootstrap;
#endif
#ifdef __OS2__
extern AudioBootStrap DART_bootstrap;
#endif
/* This is the current audio device */
extern SDL_AudioDevice *current_audio;
......
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif
/* Allow access to a raw mixing buffer */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL_types.h"
#include "SDL_error.h"
#include "SDL_timer.h"
#include "SDL_audio.h"
#include "SDL_audio_c.h"
#include "SDL_dart.h"
// Buffer states:
#define BUFFER_EMPTY 0
#define BUFFER_USED 1
typedef struct _tMixBufferDesc {
int iBufferUsage; // BUFFER_EMPTY or BUFFER_USED
SDL_AudioDevice *pSDLAudioDevice;
} tMixBufferDesc, *pMixBufferDesc;
//---------------------------------------------------------------------
// DARTEventFunc
//
// This function is called by DART, when an event occures, like end of
// playback of a buffer, etc...
//---------------------------------------------------------------------
LONG APIENTRY DARTEventFunc(ULONG ulStatus,
PMCI_MIX_BUFFER pBuffer,
ULONG ulFlags)
{
if (ulFlags && MIX_WRITE_COMPLETE)
{ // Playback of buffer completed!
// Get pointer to buffer description
pMixBufferDesc pBufDesc;
if (pBuffer)
{
pBufDesc = (pMixBufferDesc) (*pBuffer).ulUserParm;
if (pBufDesc)
{
SDL_AudioDevice *pSDLAudioDevice = pBufDesc->pSDLAudioDevice;
// Set the buffer to be empty
pBufDesc->iBufferUsage = BUFFER_EMPTY;
// And notify DART feeder thread that it will have to work a bit.
if (pSDLAudioDevice)
DosPostEventSem(pSDLAudioDevice->hidden->hevAudioBufferPlayed);
}
}
}
return TRUE;
}
int DART_OpenAudio(_THIS, SDL_AudioSpec *spec)
{
MCI_AMP_OPEN_PARMS AmpOpenParms;
MCI_GENERIC_PARMS GenericParms;
int iDeviceOrd = 0; // Default device to be used
int bOpenShared = 1; // Try opening it shared
int iBits = 16; // Default is 16 bits signed
int iFreq = 44100; // Default is 44KHz
int iChannels = 2; // Default is 2 channels (Stereo)
int iNumBufs = 2; // Number of audio buffers: 2
int iBufSize;
int iOpenMode;
int iSilence;
int rc;
// First thing is to try to open a given DART device!
memset(&AmpOpenParms, 0, sizeof(MCI_AMP_OPEN_PARMS));
// pszDeviceType should contain the device type in low word, and device ordinal in high word!
AmpOpenParms.pszDeviceType = (PSZ) (MCI_DEVTYPE_AUDIO_AMPMIX | (iDeviceOrd << 16));
iOpenMode = MCI_WAIT | MCI_OPEN_TYPE_ID;
if (bOpenShared) iOpenMode |= MCI_OPEN_SHAREABLE;
rc = mciSendCommand( 0, MCI_OPEN,
iOpenMode,
(PVOID) &AmpOpenParms, 0);
if (rc!=MCIERR_SUCCESS) // No audio available??
return (-1);
// Save the device ID we got from DART!
// We will use this in the next calls!
iDeviceOrd = AmpOpenParms.usDeviceID;
// Determine the audio parameters from the AudioSpec
switch ( spec->format & 0xFF )
{
case 8:
/* Unsigned 8 bit audio data */
spec->format = AUDIO_U8;
iSilence = 0x80;
iBits = 8;
break;
case 16:
/* Signed 16 bit audio data */
spec->format = AUDIO_S16;
iSilence = 0x00;
iBits = 16;
break;
default:
// Close DART, and exit with error code!
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
SDL_SetError("Unsupported audio format");
return(-1);
}
iFreq = spec->freq;
iChannels = spec->channels;
/* Update the fragment size as size in bytes */
SDL_CalculateAudioSpec(spec);
iBufSize = spec->size;
// Now query this device if it supports the given freq/bits/channels!
memset(&(_this->hidden->MixSetupParms), 0, sizeof(MCI_MIXSETUP_PARMS));
_this->hidden->MixSetupParms.ulBitsPerSample = iBits;
_this->hidden->MixSetupParms.ulFormatTag = MCI_WAVE_FORMAT_PCM;
_this->hidden->MixSetupParms.ulSamplesPerSec = iFreq;
_this->hidden->MixSetupParms.ulChannels = iChannels;
_this->hidden->MixSetupParms.ulFormatMode = MCI_PLAY;
_this->hidden->MixSetupParms.ulDeviceType = MCI_DEVTYPE_WAVEFORM_AUDIO;
_this->hidden->MixSetupParms.pmixEvent = DARTEventFunc;
rc = mciSendCommand (iDeviceOrd, MCI_MIXSETUP,
MCI_WAIT | MCI_MIXSETUP_QUERYMODE,
&(_this->hidden->MixSetupParms), 0);
if (rc!=MCIERR_SUCCESS)
{ // The device cannot handle this format!
// Close DART, and exit with error code!
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
SDL_SetError("Audio device doesn't support requested audio format");
return(-1);
}
// The device can handle this format, so initialize!
rc = mciSendCommand(iDeviceOrd, MCI_MIXSETUP,
MCI_WAIT | MCI_MIXSETUP_INIT,
&(_this->hidden->MixSetupParms), 0);
if (rc!=MCIERR_SUCCESS)
{ // The device could not be opened!
// Close DART, and exit with error code!
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
SDL_SetError("Audio device could not be set up");
return(-1);
}
// Ok, the device is initialized.
// Now we should allocate buffers. For this, we need a place where
// the buffer descriptors will be:
_this->hidden->pMixBuffers = (MCI_MIX_BUFFER *) malloc(sizeof(MCI_MIX_BUFFER)*iNumBufs);
if (!(_this->hidden->pMixBuffers))
{ // Not enough memory!
// Close DART, and exit with error code!
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
SDL_SetError("Not enough memory for audio buffer descriptors");
return(-1);
}
// Now that we have the place for buffer list, we can ask DART for the
// buffers!
_this->hidden->BufferParms.ulNumBuffers = iNumBufs; // Number of buffers
_this->hidden->BufferParms.ulBufferSize = iBufSize; // each with this size
_this->hidden->BufferParms.pBufList = _this->hidden->pMixBuffers; // getting descriptorts into this list
// Allocate buffers!
rc = mciSendCommand(iDeviceOrd, MCI_BUFFER,
MCI_WAIT | MCI_ALLOCATE_MEMORY,
&(_this->hidden->BufferParms), 0);
if ((rc!=MCIERR_SUCCESS) || (iNumBufs != _this->hidden->BufferParms.ulNumBuffers) || (_this->hidden->BufferParms.ulBufferSize==0))
{ // Could not allocate memory!
// Close DART, and exit with error code!
free(_this->hidden->pMixBuffers); _this->hidden->pMixBuffers = NULL;
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
SDL_SetError("DART could not allocate buffers");
return(-1);
}
// Ok, we have all the buffers allocated, let's mark them!
{
int i;
for (i=0; i<iNumBufs; i++)
{
pMixBufferDesc pBufferDesc = (pMixBufferDesc) malloc(sizeof(tMixBufferDesc));;
// Check if this buffer was really allocated by DART
if ((!(_this->hidden->pMixBuffers[i].pBuffer)) || (!pBufferDesc))
{ // Wrong buffer!
// Close DART, and exit with error code!
// Free buffer descriptions
{ int j;
for (j=0; j<i; j++) free((void *)(_this->hidden->pMixBuffers[j].ulUserParm));
}
// and cleanup
mciSendCommand(iDeviceOrd, MCI_BUFFER, MCI_WAIT | MCI_DEALLOCATE_MEMORY, &(_this->hidden->BufferParms), 0);
free(_this->hidden->pMixBuffers); _this->hidden->pMixBuffers = NULL;
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
SDL_SetError("Error at internal buffer check");
return(-1);
}
pBufferDesc->iBufferUsage = BUFFER_EMPTY;
pBufferDesc->pSDLAudioDevice = _this;
_this->hidden->pMixBuffers[i].ulBufferLength = _this->hidden->BufferParms.ulBufferSize;
_this->hidden->pMixBuffers[i].ulUserParm = (ULONG) pBufferDesc; // User parameter: Description of buffer
_this->hidden->pMixBuffers[i].ulFlags = 0; // Some stuff should be flagged here for DART, like end of
// audio data, but as we will continously send
// audio data, there will be no end.:)
memset(_this->hidden->pMixBuffers[i].pBuffer, iSilence, iBufSize);
}
}
_this->hidden->iNextFreeBuffer = 0;
_this->hidden->iLastPlayedBuf = -1;
// Create event semaphore
if (DosCreateEventSem(NULL, &(_this->hidden->hevAudioBufferPlayed), 0, FALSE)!=NO_ERROR)
{
// Could not create event semaphore!
{
int i;
for (i=0; i<iNumBufs; i++) free((void *)(_this->hidden->pMixBuffers[i].ulUserParm));
}
mciSendCommand(iDeviceOrd, MCI_BUFFER, MCI_WAIT | MCI_DEALLOCATE_MEMORY, &(_this->hidden->BufferParms), 0);
free(_this->hidden->pMixBuffers); _this->hidden->pMixBuffers = NULL;
mciSendCommand(iDeviceOrd, MCI_CLOSE, MCI_WAIT, &GenericParms, 0);
SDL_SetError("Could not create event semaphore");
return(-1);
}
// Store the new settings in global variables
_this->hidden->iCurrDeviceOrd = iDeviceOrd;
_this->hidden->iCurrFreq = iFreq;
_this->hidden->iCurrBits = iBits;
_this->hidden->iCurrChannels = iChannels;
_this->hidden->iCurrNumBufs = iNumBufs;
_this->hidden->iCurrBufSize = iBufSize;
return (0);
}
void DART_ThreadInit(_THIS)
{
return;
}
/* This function waits until it is possible to write a full sound buffer */
void DART_WaitAudio(_THIS)
{
int i;
pMixBufferDesc pBufDesc;
ULONG ulPostCount;
DosResetEventSem(_this->hidden->hevAudioBufferPlayed, &ulPostCount);
// If there is already an empty buffer, then return now!
for (i=0; i<_this->hidden->iCurrNumBufs; i++)
{
pBufDesc = (pMixBufferDesc) _this->hidden->pMixBuffers[i].ulUserParm;
if (pBufDesc->iBufferUsage == BUFFER_EMPTY)
return;
}
// If there is no empty buffer, wait for one to be empty!
DosWaitEventSem(_this->hidden->hevAudioBufferPlayed, 1000); // Wait max 1 sec!!! Important!
return;
}
void DART_PlayAudio(_THIS)
{
int iFreeBuf = _this->hidden->iNextFreeBuffer;
pMixBufferDesc pBufDesc;
pBufDesc = (pMixBufferDesc) _this->hidden->pMixBuffers[iFreeBuf].ulUserParm;
pBufDesc->iBufferUsage = BUFFER_USED;
// Send it to DART to be queued
_this->hidden->MixSetupParms.pmixWrite(_this->hidden->MixSetupParms.ulMixHandle,
&(_this->hidden->pMixBuffers[iFreeBuf]), 1);
_this->hidden->iLastPlayedBuf = iFreeBuf;
iFreeBuf = (iFreeBuf+1) % _this->hidden->iCurrNumBufs;
_this->hidden->iNextFreeBuffer = iFreeBuf;
}
Uint8 *DART_GetAudioBuf(_THIS)
{
int iFreeBuf;
Uint8 *pResult;
pMixBufferDesc pBufDesc;
if (_this)
{
if (_this->hidden)
{
iFreeBuf = _this->hidden->iNextFreeBuffer;
pBufDesc = (pMixBufferDesc) _this->hidden->pMixBuffers[iFreeBuf].ulUserParm;
if (pBufDesc)
{
if (pBufDesc->iBufferUsage == BUFFER_EMPTY)
{
pResult = _this->hidden->pMixBuffers[iFreeBuf].pBuffer;
return pResult;
}
} else
printf("[DART_GetAudioBuf] : ERROR! pBufDesc = %p\n", pBufDesc);
} else
printf("[DART_GetAudioBuf] : ERROR! _this->hidden = %p\n", _this->hidden);
} else
printf("[DART_GetAudioBuf] : ERROR! _this = %p\n", _this);
return NULL;
}
void DART_WaitDone(_THIS)
{
pMixBufferDesc pBufDesc;
ULONG ulPostCount;
APIRET rc;
pBufDesc = (pMixBufferDesc) _this->hidden->pMixBuffers[_this->hidden->iLastPlayedBuf].ulUserParm;
rc = NO_ERROR;
while ((pBufDesc->iBufferUsage != BUFFER_EMPTY) && (rc==NO_ERROR))
{
DosResetEventSem(_this->hidden->hevAudioBufferPlayed, &ulPostCount);
rc = DosWaitEventSem(_this->hidden->hevAudioBufferPlayed, 1000); // 1 sec timeout! Important!
}
}
void DART_CloseAudio(_THIS)
{
MCI_GENERIC_PARMS GenericParms;
int rc;
// Stop DART playback
rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_STOP, MCI_WAIT, &GenericParms, 0);
if (rc!=MCIERR_SUCCESS)
{
#ifdef SFX_DEBUG_BUILD
printf("Could not stop DART playback!\n");
fflush(stdout);
#endif
}
// Close event semaphore
DosCloseEventSem(_this->hidden->hevAudioBufferPlayed);
// Free memory of buffer descriptions
{
int i;
for (i=0; i<_this->hidden->iCurrNumBufs; i++) free((void *)(_this->hidden->pMixBuffers[i].ulUserParm));
}
// Deallocate buffers
rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_BUFFER, MCI_WAIT | MCI_DEALLOCATE_MEMORY, &(_this->hidden->BufferParms), 0);
// Free bufferlist
free(_this->hidden->pMixBuffers); _this->hidden->pMixBuffers = NULL;
// Close dart
rc = mciSendCommand(_this->hidden->iCurrDeviceOrd, MCI_CLOSE, MCI_WAIT, &(GenericParms), 0);
}
/* Audio driver bootstrap functions */
int Audio_Available(void)
{
return(1);
}
void Audio_DeleteDevice(SDL_AudioDevice *device)
{
free(device->hidden);
free(device);
}
SDL_AudioDevice *Audio_CreateDevice(int devindex)
{
SDL_AudioDevice *this;
/* Initialize all variables that we clean on shutdown */
this = (SDL_AudioDevice *)malloc(sizeof(SDL_AudioDevice));
if ( this )
{
memset(this, 0, (sizeof *this));
this->hidden = (struct SDL_PrivateAudioData *)
malloc((sizeof *this->hidden));
}
if ( (this == NULL) || (this->hidden == NULL) )
{
SDL_OutOfMemory();
if ( this )
free(this);
return(0);
}
memset(this->hidden, 0, (sizeof *this->hidden));
/* Set the function pointers */
this->OpenAudio = DART_OpenAudio;
this->ThreadInit = DART_ThreadInit;
this->WaitAudio = DART_WaitAudio;
this->PlayAudio = DART_PlayAudio;
this->GetAudioBuf = DART_GetAudioBuf;
this->WaitDone = DART_WaitDone;
this->CloseAudio = DART_CloseAudio;
this->free = Audio_DeleteDevice;
return this;
}
AudioBootStrap DART_bootstrap = {
"dart", "OS/2 Direct Audio RouTines (DART)",
Audio_Available, Audio_CreateDevice
};
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif
#ifndef _SDL_lowaudio_h
#define _SDL_lowaudio_h
#include "SDL_sysaudio.h"
#define INCL_TYPES
#define INCL_DOSSEMAPHORES
#define INCL_DOSRESOURCES
#define INCL_DOSMISC
#define INCL_DOSERRORS
#define INCL_OS2MM
#define INCL_MMIOOS2
#define INCL_MCIOS2
#include <os2.h>
#include <os2me.h> // DART stuff and MMIO stuff
/* Hidden "this" pointer for the audio functions */
#define _THIS SDL_AudioDevice *_this
/* The DirectSound objects */
struct SDL_PrivateAudioData
{
int iCurrDeviceOrd;
int iCurrFreq;
int iCurrBits;
int iCurrChannels;
int iCurrNumBufs;
int iCurrBufSize;
int iLastPlayedBuf;
int iNextFreeBuffer;
MCI_BUFFER_PARMS BufferParms; // Sound buffer parameters
MCI_MIX_BUFFER *pMixBuffers; // Sound buffers
MCI_MIXSETUP_PARMS MixSetupParms; // Mixer setup parameters
HEV hevAudioBufferPlayed; // Event semaphore to indicate that an audio buffer has been played by DART
};
#endif /* _SDL_lowaudio_h */
#=============================================================================
# This is a Watcom makefile to build SDL.DLL for OS/2
#
# Makefile for OS/2 System CDROM support
#=============================================================================
object_files=SDL_syscdrom.obj SDL_cdrom.obj
ExtraCFlags=
#
#==============================================================================
#
!include ..\..\Watcom.mif
.before
set include=$(%os2tk)\h;$(%include);../../include;./os2;../;
all : $(object_files)
SDL_syscdrom.obj : .AUTODEPEND
wcc386 os2\SDL_syscdrom.c $(cflags)
SDL_cdrom.obj : .AUTODEPEND
wcc386 SDL_cdrom.c $(cflags)
clean : .SYMBOLIC
@if exist *.obj del *.obj
@if exist *.map del *.map
@if exist *.res del *.res
@if exist *.lst del *.lst
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2004 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif
/* Functions for system-level CD-ROM audio control */
#define INCL_MCIOS2
#include <os2.h>
#include <os2me.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "SDL_error.h"
#include "SDL_cdrom.h"
#include "SDL_syscdrom.h"
/* Size of MCI result buffer (in bytes) */
#define MCI_CMDRETBUFSIZE 128
/* The maximum number of CD-ROM drives we'll detect */
#define MAX_DRIVES 16
/* A list of available CD-ROM drives */
static char *SDL_cdlist[MAX_DRIVES];
//static dev_t SDL_cdmode[MAX_DRIVES];
/* The system-dependent CD control functions */
static const char *SDL_SYS_CDName(int drive);
static int SDL_SYS_CDOpen(int drive);
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom);
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position);
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length);
static int SDL_SYS_CDPause(SDL_CD *cdrom);
static int SDL_SYS_CDResume(SDL_CD *cdrom);
static int SDL_SYS_CDStop(SDL_CD *cdrom);
static int SDL_SYS_CDEject(SDL_CD *cdrom);
static void SDL_SYS_CDClose(SDL_CD *cdrom);
/* MCI Timing Functions */
#define MCI_MMTIMEPERSECOND 3000
#define FRAMESFROMMM(mmtime) (((mmtime)*CD_FPS)/MCI_MMTIMEPERSECOND)
/* Ready for MCI CDAudio Devices */
int SDL_SYS_CDInit(void)
{
int i; /* generig counter */
MCI_SYSINFO_PARMS msp; /* Structure to MCI SysInfo parameters */
CHAR SysInfoRet[MCI_CMDRETBUFSIZE]; /* Buffer for MCI Command result */
/* Fill in our driver capabilities */
SDL_CDcaps.Name = SDL_SYS_CDName;
SDL_CDcaps.Open = SDL_SYS_CDOpen;
SDL_CDcaps.GetTOC = SDL_SYS_CDGetTOC;
SDL_CDcaps.Status = SDL_SYS_CDStatus;
SDL_CDcaps.Play = SDL_SYS_CDPlay;
SDL_CDcaps.Pause = SDL_SYS_CDPause;
SDL_CDcaps.Resume = SDL_SYS_CDResume;
SDL_CDcaps.Stop = SDL_SYS_CDStop;
SDL_CDcaps.Eject = SDL_SYS_CDEject;
SDL_CDcaps.Close = SDL_SYS_CDClose;
/* Get the number of CD ROMs in the System */
/* Clean SysInfo structure */
memset(&msp, 0x00, sizeof(MCI_SYSINFO_PARMS));
/* Prepare structure to Ask Numer of Audio CDs */
msp.usDeviceType = MCI_DEVTYPE_CD_AUDIO; /* CD Audio Type */
msp.pszReturn = (PSZ)&SysInfoRet; /* Return Structure */
msp.ulRetSize = MCI_CMDRETBUFSIZE; /* Size of ret struct */
if (LOUSHORT(mciSendCommand(0,MCI_SYSINFO, MCI_SYSINFO_QUANTITY | MCI_WAIT, (PVOID)&msp, 0)) != MCIERR_SUCCESS) return(CD_ERROR);
SDL_numcds = atoi(SysInfoRet);
if (SDL_numcds > MAX_DRIVES) SDL_numcds = MAX_DRIVES; /* Limit maximum CD number */
/* Get and Add their system name to the SDL_cdlist */
msp.pszReturn = (PSZ)&SysInfoRet; /* Return Structure */
msp.ulRetSize = MCI_CMDRETBUFSIZE; /* Size of ret struct */
msp.usDeviceType = MCI_DEVTYPE_CD_AUDIO; /* CD Audio Type */
for (i=0; i<SDL_numcds; i++)
{
msp.ulNumber = i+1;
mciSendCommand(0,MCI_SYSINFO, MCI_SYSINFO_NAME | MCI_WAIT,&msp, 0);
SDL_cdlist[i] = (char *)malloc(strlen(SysInfoRet)+1);
if ( SDL_cdlist[i] == NULL )
{
SDL_OutOfMemory();
return(-1);
}
strcpy(SDL_cdlist[i], SysInfoRet);
}
return(0);
}
/* Return CDAudio System Dependent Device Name - Ready for MCI*/
static const char *SDL_SYS_CDName(int drive)
{
return(SDL_cdlist[drive]);
}
/* Open CDAudio Device - Ready for MCI */
static int SDL_SYS_CDOpen(int drive)
{
MCI_OPEN_PARMS mop;
MCI_SET_PARMS msp;
MCI_GENERIC_PARMS mgp;
/* Open the device */
mop.hwndCallback = (HWND)NULL; // None
mop.usDeviceID = (USHORT)NULL; // Will be returned.
mop.pszDeviceType = (PSZ)SDL_cdlist[drive]; // CDAudio Device
if (LOUSHORT(mciSendCommand(0,MCI_OPEN,MCI_WAIT,&mop, 0)) != MCIERR_SUCCESS) return(CD_ERROR);
/* Set time format */
msp.hwndCallback = (HWND)NULL; // None
msp.ulTimeFormat = MCI_FORMAT_MSF; // Minute : Second : Frame structure
msp.ulSpeedFormat = (ULONG)NULL; // No change
msp.ulAudio = (ULONG)NULL; // No Channel
msp.ulLevel = (ULONG)NULL; // No Volume
msp.ulOver = (ULONG)NULL; // No Delay
msp.ulItem = (ULONG)NULL; // No item
msp.ulValue = (ULONG)NULL; // No value for item flag
if (LOUSHORT(mciSendCommand(mop.usDeviceID,MCI_SET,MCI_WAIT | MCI_SET_TIME_FORMAT,&msp, 0)) == MCIERR_SUCCESS) return (mop.usDeviceID);
/* Error setting time format? - Close opened device */
mgp.hwndCallback = (HWND)NULL; // None
mciSendCommand(mop.usDeviceID,MCI_CLOSE,MCI_WAIT,&mgp, 0);
return(CD_ERROR);
}
/* Get CD Table Of Contents - Ready for MCI */
static int SDL_SYS_CDGetTOC(SDL_CD *cdrom)
{
MCI_TOC_PARMS mtp;
MCI_STATUS_PARMS msp;
MCI_TOC_REC * mtr;
INT i;
/* Correction because MCI cannot read TOC while CD is playing (it'll stop!) */
if (cdrom->status == CD_PLAYING || cdrom->status == CD_PAUSED) return 0;
/* Get Number of Tracks */
msp.hwndCallback = (HWND)NULL; /* None */
msp.ulReturn = (ULONG)NULL; /* We want this information */
msp.ulItem = MCI_STATUS_NUMBER_OF_TRACKS;
msp.ulValue = (ULONG)NULL; /* No additional information */
if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) return(CD_ERROR);
cdrom->numtracks = msp.ulReturn;
if ( cdrom->numtracks > SDL_MAX_TRACKS )
{
cdrom->numtracks = SDL_MAX_TRACKS;
}
/* Alocate space for TOC data */
mtr = (MCI_TOC_REC *)malloc(cdrom->numtracks*sizeof(MCI_TOC_REC));
if ( mtr == NULL )
{
SDL_OutOfMemory();
return(-1);
}
/* Get TOC from CD */
mtp.pBuf = mtr;
mtp.ulBufSize = cdrom->numtracks*sizeof(MCI_TOC_REC);
if (LOUSHORT(mciSendCommand(cdrom->id,MCI_GETTOC,MCI_WAIT,&mtp, 0)) != MCIERR_SUCCESS)
{
SDL_OutOfMemory();
free(mtr);
return(CD_ERROR);
}
/* Fill SDL Tracks Structure */
for (i=0; i<cdrom->numtracks; i++)
{
/* Set Track ID */
cdrom->track[i].id = (mtr+i)->TrackNum;
/* Set Track Type */
msp.hwndCallback = (HWND)NULL; /* None */
msp.ulReturn = (ULONG)NULL; /* We want this information */
msp.ulItem = MCI_CD_STATUS_TRACK_TYPE;
msp.ulValue = (ULONG)((mtr+i)->TrackNum); /* Track Number? */
if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_TRACK | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS)
{
free(mtr);
return (CD_ERROR);
}
if (msp.ulReturn==MCI_CD_TRACK_AUDIO) cdrom->track[i].type = SDL_AUDIO_TRACK;
else cdrom->track[i].type = SDL_DATA_TRACK;
/* Set Track Length - values from MCI are in MMTIMEs - 3000 MMTIME = 1 second */
cdrom->track[i].length = FRAMESFROMMM((mtr+i)->ulEndAddr - (mtr+i)->ulStartAddr);
/* Set Track Offset */
cdrom->track[i].offset = FRAMESFROMMM((mtr+i)->ulStartAddr);
}
free(mtr);
return(0);
}
/* Get CD-ROM status - Ready for MCI */
static CDstatus SDL_SYS_CDStatus(SDL_CD *cdrom, int *position)
{
CDstatus status;
MCI_STATUS_PARMS msp;
/* Get Status from MCI */
msp.hwndCallback = (HWND)NULL; /* None */
msp.ulReturn = (ULONG)NULL; /* We want this information */
msp.ulItem = MCI_STATUS_MODE;
msp.ulValue = (ULONG)NULL; /* No additional information */
if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) status = CD_ERROR;
else
{
switch(msp.ulReturn)
{
case MCI_MODE_NOT_READY:
status = CD_TRAYEMPTY;
break;
case MCI_MODE_PAUSE:
status = CD_PAUSED;
break;
case MCI_MODE_PLAY:
status = CD_PLAYING;
break;
case MCI_MODE_STOP:
status = CD_STOPPED;
break;
/* These cases should not occour */
case MCI_MODE_RECORD:
case MCI_MODE_SEEK:
default:
status = CD_ERROR;
break;
}
}
/* Determine position */
if (position != NULL) /* The SDL $&$&%# CDROM call sends NULL pointer here! */
{
if ((status == CD_PLAYING) || (status == CD_PAUSED))
{
/* Get Position */
msp.hwndCallback = (HWND)NULL; /* None */
msp.ulReturn = (ULONG)NULL; /* We want this information */
msp.ulItem = MCI_STATUS_POSITION;
msp.ulValue = (ULONG)NULL; /* No additiona info */
if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) != MCIERR_SUCCESS) return (CD_ERROR);
/* Convert from MSF (format selected in the Open process) to Frames (format that will be returned) */
*position = MSF_TO_FRAMES(MSF_MINUTE(msp.ulReturn),MSF_SECOND(msp.ulReturn),MSF_FRAME(msp.ulReturn));
}
else *position = 0;
}
return(status);
}
/* Start play - Ready for MCI */
static int SDL_SYS_CDPlay(SDL_CD *cdrom, int start, int length)
{
MCI_GENERIC_PARMS mgp;
MCI_STATUS_PARMS msp;
MCI_PLAY_PARMS mpp;
ULONG min,sec,frm;
/* Start MSF */
FRAMES_TO_MSF(start, &min, &sec, &frm);
MSF_MINUTE(mpp.ulFrom) = min;
MSF_SECOND(mpp.ulFrom) = sec;
MSF_FRAME(mpp.ulFrom) = frm;
/* End MSF */
FRAMES_TO_MSF(start+length, &min, &sec, &frm);
MSF_MINUTE(mpp.ulTo) = min;
MSF_SECOND(mpp.ulTo) = sec;
MSF_FRAME(mpp.ulTo) = frm;
#ifdef DEBUG_CDROM
fprintf(stderr, "Trying to play from %d:%d:%d to %d:%d:%d\n",
playtime.cdmsf_min0, playtime.cdmsf_sec0, playtime.cdmsf_frame0,
playtime.cdmsf_min1, playtime.cdmsf_sec1, playtime.cdmsf_frame1);
#endif
/* Verifies if it is paused first... and if it is, unpause before stopping it. */
msp.hwndCallback = (HWND)NULL; /* None */
msp.ulReturn = (ULONG)NULL; /* We want this information */
msp.ulItem = MCI_STATUS_MODE;
msp.ulValue = (ULONG)NULL; /* No additional information */
if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) == MCIERR_SUCCESS)
{
if (msp.ulReturn == MCI_MODE_PAUSE)
{
mgp.hwndCallback = (HWND)NULL; // None
mciSendCommand(cdrom->id,MCI_RESUME,NULL,&mgp, 0);
}
}
/* Now play it. */
mpp.hwndCallback = (HWND)NULL; // We do not want the info. temp
if (LOUSHORT(mciSendCommand(cdrom->id,MCI_PLAY,MCI_FROM | MCI_TO,&mpp, 0)) == MCIERR_SUCCESS) return 0;
return (CD_ERROR);
}
/* Pause play - Ready for MCI */
static int SDL_SYS_CDPause(SDL_CD *cdrom)
{
MCI_GENERIC_PARMS mgp;
mgp.hwndCallback = (HWND)NULL; // None
if (LOUSHORT(mciSendCommand(cdrom->id,MCI_PAUSE,MCI_WAIT,&mgp, 0)) == MCIERR_SUCCESS) return 0;
return(CD_ERROR);
}
/* Resume play - Ready for MCI */
static int SDL_SYS_CDResume(SDL_CD *cdrom)
{
MCI_GENERIC_PARMS mgp;
mgp.hwndCallback = (HWND)NULL; // None
if (LOUSHORT(mciSendCommand(cdrom->id,MCI_RESUME,MCI_WAIT,&mgp, 0)) == MCIERR_SUCCESS) return 0;
return(CD_ERROR);
}
/* Stop play - Ready for MCI */
static int SDL_SYS_CDStop(SDL_CD *cdrom)
{
MCI_GENERIC_PARMS mgp;
MCI_STATUS_PARMS msp;
/* Verifies if it is paused first... and if it is, unpause before stopping it. */
msp.hwndCallback = (HWND)NULL; /* None */
msp.ulReturn = (ULONG)NULL; /* We want this information */
msp.ulItem = MCI_STATUS_MODE;
msp.ulValue = (ULONG)NULL; /* No additional information */
if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STATUS,MCI_WAIT | MCI_STATUS_ITEM,&msp, 0)) == MCIERR_SUCCESS)
{
if (msp.ulReturn == MCI_MODE_PAUSE)
{
mgp.hwndCallback = (HWND)NULL; // None
mciSendCommand(cdrom->id,MCI_RESUME,NULL,&mgp, 0);
}
}
/* Now stops the media */
mgp.hwndCallback = (HWND)NULL; // None
if (LOUSHORT(mciSendCommand(cdrom->id,MCI_STOP,MCI_WAIT,&mgp, 0)) == MCIERR_SUCCESS) return 0;
return(CD_ERROR);
}
/* Eject the CD-ROM - Ready for MCI */
static int SDL_SYS_CDEject(SDL_CD *cdrom)
{
MCI_SET_PARMS msp;
msp.hwndCallback = (HWND)NULL; // None
msp.ulTimeFormat = (ULONG)NULL; // No change
msp.ulSpeedFormat = (ULONG)NULL; // No change
msp.ulAudio = (ULONG)NULL; // No Channel
msp.ulLevel = (ULONG)NULL; // No Volume
msp.ulOver = (ULONG)NULL; // No Delay
msp.ulItem = (ULONG)NULL; // No item
msp.ulValue = (ULONG)NULL; // No value for item flag
if (LOUSHORT(mciSendCommand(cdrom->id,MCI_SET,MCI_WAIT | MCI_SET_DOOR_OPEN,&msp, 0)) == MCIERR_SUCCESS) return 0;
return(CD_ERROR);
}
/* Close the CD-ROM handle - Ready for MCI */
static void SDL_SYS_CDClose(SDL_CD *cdrom)
{
MCI_GENERIC_PARMS mgp;
mgp.hwndCallback = (HWND)NULL; // None
mciSendCommand(cdrom->id,MCI_CLOSE,MCI_WAIT,&mgp, 0);
}
/* Finalize CDROM Subsystem - Ready for MCI */
void SDL_SYS_CDQuit(void)
{
int i;
if ( SDL_numcds > 0 )
{
for ( i=0; i<SDL_numcds; ++i )
{
free(SDL_cdlist[i]);
}
SDL_numcds = 0;
}
}
#=============================================================================
# This is a Watcom makefile to build SDL.DLL for OS/2
#
# Makefile for cpuinfo
#=============================================================================
object_files=SDL_cpuinfo.obj
# We have to define the following so the assembly parts can be
# compiled by Watcom, too!
ExtraCFlags=-d_MSC_VER
#
#==============================================================================
#
!include ..\..\Watcom.mif
.before
set include=$(%os2tk)\h;$(%include);../../include
all : $(object_files)
clean : .SYMBOLIC
@if exist *.obj del *.obj
@if exist *.map del *.map
@if exist *.res del *.res
@if exist *.lst del *.lst
#=============================================================================
# This is a Watcom makefile to build SDL.DLL for OS/2
#
# Makefile for endianness
#=============================================================================
object_files=SDL_endian.obj
ExtraCFlags=
#
#==============================================================================
#
!include ..\..\Watcom.mif
.before
set include=$(%os2tk)\h;$(%include);../../include
all : $(object_files)
clean : .SYMBOLIC
@if exist *.obj del *.obj
@if exist *.map del *.map
@if exist *.res del *.res
@if exist *.lst del *.lst
#=============================================================================
# This is a Watcom makefile to build SDL.DLL for OS/2
#
# Makefile for events
#=============================================================================
object_files=SDL_active.obj SDL_events.obj SDL_expose.obj SDL_keyboard.obj SDL_mouse.obj SDL_quit.obj SDL_resize.obj
ExtraCFlags=-dUSE_DOSSETPRIORITY
#
#==============================================================================
#
!include ..\..\Watcom.mif
.before
set include=$(%os2tk)\h;$(%include);../../include;../timer;../joystick;../video;
all : $(object_files)
clean : .SYMBOLIC
@if exist *.obj del *.obj
@if exist *.map del *.map
@if exist *.res del *.res
@if exist *.lst del *.lst
......@@ -89,9 +89,28 @@ void SDL_Unlock_EventThread(void)
}
}
#ifdef __OS2__
/*
* We'll increase the priority of GobbleEvents thread, so it will process
* events in time for sure! For this, we need the DosSetPriority() API
* from the os2.h include file.
*/
#define INCL_DOSPROCESS
#include <os2.h>
#include <time.h>
#endif
static int SDL_GobbleEvents(void *unused)
{
event_thread = SDL_ThreadID();
#ifdef __OS2__
#ifdef USE_DOSSETPRIORITY
/* Increase thread priority, so it will process events in time for sure! */
DosSetPriority(PRTYS_THREAD, PRTYC_REGULAR, +16, 0);
#endif
#endif
while ( SDL_EventQ.active ) {
SDL_VideoDevice *video = current_video;
SDL_VideoDevice *this = current_video;
......
......@@ -45,8 +45,11 @@ int SDL_PrivateResize(int w, int h)
SDL_Event events[32];
/* See if this event would change the video surface */
if ( !w || !h ||
((last_resize.w == w) && (last_resize.h == h)) ) {
if ( !w || !h
#ifndef __OS2__
|| ((last_resize.w == w) && (last_resize.h == h))
#endif
) {
return(0);
}
last_resize.w = w;
......
......@@ -44,3 +44,7 @@ static char rcsid =
#ifdef macintosh /* MacOS 7/8 don't support preemptive multi-tasking */
#define CANT_THREAD_EVENTS
#endif
#ifdef __OS2__ /* The OS/2 event loop runs in a separate thread */
#define MUST_THREAD_EVENTS
#endif
#=============================================================================
# This is a Watcom makefile to build SDL.DLL for OS/2
#
# Makefile for file
#=============================================================================
object_files=SDL_rwops.obj
ExtraCFlags=
#
#==============================================================================
#
!include ..\..\Watcom.mif
.before
set include=$(%os2tk)\h;$(%include);../../include
all : $(object_files)
clean : .SYMBOLIC
@if exist *.obj del *.obj
@if exist *.map del *.map
@if exist *.res del *.res
@if exist *.lst del *.lst
#=============================================================================
# This is a Watcom makefile to build SDL.DLL for OS/2
#
# Makefile for joystick (using the dummy joystick driver)
#=============================================================================
object_files=SDL_joystick.obj SDL_sysjoystick.obj
ExtraCFlags=
#
#==============================================================================
#
!include ..\..\Watcom.mif
.before
set include=$(%os2tk)\h;$(%include);../../include;./os2;../;../events;
all : $(object_files)
SDL_sysjoystick.obj: .AUTODEPEND
wcc386 os2\SDL_sysjoystick.c $(cflags)
clean : .SYMBOLIC
@if exist *.obj del *.obj
@if exist *.map del *.map
@if exist *.res del *.res
@if exist *.lst del *.lst
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2004 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif
/* OS/2 Joystick driver, contributed by Daniel Caetano */
#include <stdlib.h>
#include <stdio.h>
#include <mem.h>
#define INCL_DOSDEVICES
#define INCL_DOSDEVIOCTL
#define INCL_DOSMEMMGR
#include <os2.h>
#include "joyos2.h"
#include "SDL_error.h"
#include "SDL_joystick.h"
#include "SDL_sysjoystick.h"
#include "SDL_joystick_c.h"
HFILE hJoyPort = NULL; /* Joystick GAME$ Port Address */
#define MAX_JOYSTICKS 2 /* Maximum of two joysticks */
#define MAX_AXES 4 /* each joystick can have up to 4 axes */
#define MAX_BUTTONS 8 /* 8 buttons */
#define MAX_HATS 0 /* 0 hats - OS/2 doesn't support it */
#define MAX_BALLS 0 /* and 0 balls - OS/2 doesn't support it */
#define AXIS_MIN -32768 /* minimum value for axes coordinate */
#define AXIS_MAX 32767 /* maximum value for axes coordinate */
#define MAX_JOYNAME 128 /* Joystick name may have 128 characters */
/* limit axes to 256 possible positions to filter out noise */
#define JOY_AXIS_THRESHOLD (((AXIS_MAX)-(AXIS_MIN))/256)
/* Calc Button Flag for buttons A to D */
#define JOY_BUTTON_FLAG(n) (1<<n)
/* Joystick data... hold information about detected devices */
struct _SYS_JoyData
{
Sint8 id; // Device ID
char szDeviceName[MAX_JOYNAME]; // Device Name
char axes; // Number of axes
char buttons; // Number of buttons
char hats; // Number of buttons
char balls; // Number of buttons
int axes_min[MAX_AXES]; // minimum callibration value for axes
int axes_med[MAX_AXES]; // medium callibration value for axes
int axes_max[MAX_AXES]; // maximum callibration value for axes
int buttoncalc[4]; // Used for buttons 5, 6, 7 and 8.
} SYS_JoyData[MAX_JOYSTICKS];
/* Structure used to convert data from OS/2 driver format to SDL format */
struct joystick_hwdata
{
Sint8 id;
struct _transaxes
{
int offset; /* Center Offset */
float scale1; /* Center to left/up Scale */
float scale2; /* Center to right/down Scale */
} transaxes[MAX_AXES];
};
/* Structure used to get values from Joystick Environment Variable */
struct _joycfg
{
char name[MAX_JOYNAME];
unsigned int axes;
unsigned int buttons;
unsigned int hats;
unsigned int balls;
};
/* OS/2 Implementation Function Prototypes */
APIRET joyPortOpen(HFILE * hGame);
void joyPortClose(HFILE * hGame);
int joyGetData(char *joyenv, char *name, char stopchar, size_t maxchars);
int joyGetEnv(struct _joycfg * joydata);
/************************************************************************/
/* Function to scan the system for joysticks. */
/* This function should set SDL_numjoysticks to the number of available */
/* joysticks. Joystick 0 should be the system default joystick. */
/* It should return 0, or -1 on an unrecoverable fatal error. */
/************************************************************************/
int SDL_SYS_JoystickInit(void)
{
APIRET rc; /* Generic OS/2 return code */
GAME_PORT_STRUCT stJoyStatus; /* Joystick Status Structure */
GAME_PARM_STRUCT stGameParms; /* Joystick Parameter Structure */
GAME_CALIB_STRUCT stGameCalib; /* Calibration Struct */
ULONG ulDataLen; /* Size of data */
ULONG ulLastTick; /* Tick Counter for timing operations */
Uint8 maxdevs; /* Maximum number of devices */
Uint8 numdevs; /* Number of present devices */
Uint8 maxbut; /* Maximum number of buttons... */
Uint8 i; /* Temporary Count Vars */
Uint8 ucNewJoystickMask; /* Mask for Joystick Detection */
struct _joycfg joycfg; /* Joy Configuration from envvar */
/* Get Max Number of Devices */
rc = joyPortOpen(&hJoyPort); /* Open GAME$ port */
if (rc != 0) return 0; /* Cannot open... report no joystick */
ulDataLen = sizeof(stGameParms);
rc = DosDevIOCtl(hJoyPort, IOCTL_CAT_USER, GAME_GET_PARMS,
NULL, 0, NULL, &stGameParms, ulDataLen, &ulDataLen); /* Ask device info */
if (rc != 0)
{
joyPortClose(&hJoyPort);
SDL_SetError("Could not read joystick port.");
return -1;
}
if (stGameParms.useA != 0) maxdevs++;
if (stGameParms.useB != 0) maxdevs++;
if ( maxdevs > MAX_JOYSTICKS ) maxdevs = MAX_JOYSTICKS;
/* Defines min/max axes values (callibration) */
ulDataLen = sizeof(stGameCalib);
rc = DosDevIOCtl(hJoyPort, IOCTL_CAT_USER, GAME_GET_CALIB,
NULL, 0, NULL, &stGameCalib, ulDataLen, &ulDataLen);
if (rc != 0)
{
joyPortClose(&hJoyPort);
SDL_SetError("Could not read callibration data.");
return -1;
}
/* Determine how many joysticks are active */
numdevs = 0; /* Points no device */
ucNewJoystickMask = 0x0F; /* read all 4 joystick axis */
ulDataLen = sizeof(ucNewJoystickMask);
rc = DosDevIOCtl(hJoyPort, IOCTL_CAT_USER, GAME_PORT_RESET,
&ucNewJoystickMask, ulDataLen, &ulDataLen, NULL, 0, NULL);
if (rc == 0)
{
ulDataLen = sizeof(stJoyStatus);
rc = DosDevIOCtl(hJoyPort, IOCTL_CAT_USER, GAME_PORT_GET,
NULL, 0, NULL, &stJoyStatus, ulDataLen, &ulDataLen);
if (rc != 0)
{
joyPortClose(&hJoyPort);
SDL_SetError("Could not call joystick port.");
return -1;
}
ulLastTick = stJoyStatus.ulJs_Ticks;
while (stJoyStatus.ulJs_Ticks == ulLastTick)
{
rc = DosDevIOCtl(hJoyPort, IOCTL_CAT_USER, GAME_PORT_GET,
NULL, 0, NULL, &stJoyStatus, ulDataLen, &ulDataLen);
}
if ((stJoyStatus.ucJs_JoyStickMask & 0x03) > 0) numdevs++;
if (((stJoyStatus.ucJs_JoyStickMask >> 2) & 0x03) > 0) numdevs++;
}
if (numdevs>maxdevs) numdevs=maxdevs;
/* If *any* joystick was detected... Let's configure SDL for them */
if (numdevs > 0)
{
/* Verify if it is a "user defined" joystick */
if (joyGetEnv(&joycfg))
{
GAME_3POS_STRUCT * axis[4];
axis[0] = &stGameCalib.Ax;
axis[1] = &stGameCalib.Ay;
axis[2] = &stGameCalib.Bx;
axis[3] = &stGameCalib.By;
/* Say it has one device only (user defined is always one device only) */
numdevs = 1;
/* Define Device 0 as... */
SYS_JoyData[0].id=0;
/* Define Number of Axes... up to 4 */
if (joycfg.axes>MAX_AXES) joycfg.axes = MAX_AXES;
SYS_JoyData[0].axes = joycfg.axes;
/* Define number of buttons... 8 if 2 axes, 6 if 3 axes and 4 if 4 axes */
maxbut = MAX_BUTTONS;
if (joycfg.axes>2) maxbut-=((joycfg.axes-2)<<1); /* MAX_BUTTONS - 2*(axes-2) */
if (joycfg.buttons > maxbut) joycfg.buttons = maxbut;
SYS_JoyData[0].buttons = joycfg.buttons;
/* Define number of hats */
if (joycfg.hats > MAX_HATS) joycfg.hats = MAX_HATS;
SYS_JoyData[0].hats = joycfg.hats;
/* Define number of balls */
if (joycfg.balls > MAX_BALLS) joycfg.balls = MAX_BALLS;
SYS_JoyData[0].balls = joycfg.balls;
/* Initialize Axes Callibration Values */
for (i=0; i<joycfg.axes; i++)
{
SYS_JoyData[0].axes_min[i] = axis[i]->lower;
SYS_JoyData[0].axes_med[i] = axis[i]->centre;
SYS_JoyData[0].axes_max[i] = axis[i]->upper;
}
/* Initialize Buttons 5 to 8 structures */
if (joycfg.buttons>=5) SYS_JoyData[0].buttoncalc[0]=((axis[2]->lower+axis[3]->centre)>>1);
if (joycfg.buttons>=6) SYS_JoyData[0].buttoncalc[1]=((axis[3]->lower+axis[3]->centre)>>1);
if (joycfg.buttons>=7) SYS_JoyData[0].buttoncalc[2]=((axis[2]->upper+axis[3]->centre)>>1);
if (joycfg.buttons>=8) SYS_JoyData[0].buttoncalc[3]=((axis[3]->upper+axis[3]->centre)>>1);
/* Intialize Joystick Name */
strcpy (SYS_JoyData[0].szDeviceName,joycfg.name);
}
/* Default Init ... autoconfig */
else
{
/* if two devices were detected... configure as Joy1 4 axis and Joy2 2 axis */
if (numdevs==2)
{
/* Define Device 0 as 4 axes, 4 buttons */
SYS_JoyData[0].id=0;
SYS_JoyData[0].axes = 4;
SYS_JoyData[0].buttons = 4;
SYS_JoyData[0].hats = 0;
SYS_JoyData[0].balls = 0;
SYS_JoyData[0].axes_min[0] = stGameCalib.Ax.lower;
SYS_JoyData[0].axes_med[0] = stGameCalib.Ax.centre;
SYS_JoyData[0].axes_max[0] = stGameCalib.Ax.upper;
SYS_JoyData[0].axes_min[1] = stGameCalib.Ay.lower;
SYS_JoyData[0].axes_med[1] = stGameCalib.Ay.centre;
SYS_JoyData[0].axes_max[1] = stGameCalib.Ay.upper;
SYS_JoyData[0].axes_min[2] = stGameCalib.Bx.lower;
SYS_JoyData[0].axes_med[2] = stGameCalib.Bx.centre;
SYS_JoyData[0].axes_max[2] = stGameCalib.Bx.upper;
SYS_JoyData[0].axes_min[3] = stGameCalib.By.lower;
SYS_JoyData[0].axes_med[3] = stGameCalib.By.centre;
SYS_JoyData[0].axes_max[3] = stGameCalib.By.upper;
/* Define Device 1 as 2 axes, 2 buttons */
SYS_JoyData[1].id=1;
SYS_JoyData[1].axes = 2;
SYS_JoyData[1].buttons = 2;
SYS_JoyData[1].hats = 0;
SYS_JoyData[1].balls = 0;
SYS_JoyData[1].axes_min[0] = stGameCalib.Bx.lower;
SYS_JoyData[1].axes_med[0] = stGameCalib.Bx.centre;
SYS_JoyData[1].axes_max[0] = stGameCalib.Bx.upper;
SYS_JoyData[1].axes_min[1] = stGameCalib.By.lower;
SYS_JoyData[1].axes_med[1] = stGameCalib.By.centre;
SYS_JoyData[1].axes_max[1] = stGameCalib.By.upper;
}
/* One joystick only? */
else
{
/* If it is joystick A... */
if ((stJoyStatus.ucJs_JoyStickMask & 0x03) > 0)
{
/* Define Device 0 as 2 axes, 4 buttons */
SYS_JoyData[0].id=0;
SYS_JoyData[0].axes = 2;
SYS_JoyData[0].buttons = 4;
SYS_JoyData[0].hats = 0;
SYS_JoyData[0].balls = 0;
SYS_JoyData[0].axes_min[0] = stGameCalib.Ax.lower;
SYS_JoyData[0].axes_med[0] = stGameCalib.Ax.centre;
SYS_JoyData[0].axes_max[0] = stGameCalib.Ax.upper;
SYS_JoyData[0].axes_min[1] = stGameCalib.Ay.lower;
SYS_JoyData[0].axes_med[1] = stGameCalib.Ay.centre;
SYS_JoyData[0].axes_max[1] = stGameCalib.Ay.upper;
}
/* If not, it is joystick B */
else
{
/* Define Device 1 as 2 axes, 2 buttons */
SYS_JoyData[0].id=1;
SYS_JoyData[0].axes = 2;
SYS_JoyData[0].buttons = 2;
SYS_JoyData[0].hats = 0;
SYS_JoyData[0].balls = 0;
SYS_JoyData[0].axes_min[0] = stGameCalib.Bx.lower;
SYS_JoyData[0].axes_med[0] = stGameCalib.Bx.centre;
SYS_JoyData[0].axes_max[0] = stGameCalib.Bx.upper;
SYS_JoyData[0].axes_min[1] = stGameCalib.By.lower;
SYS_JoyData[0].axes_med[1] = stGameCalib.By.centre;
SYS_JoyData[0].axes_max[1] = stGameCalib.By.upper;
}
}
/* Hack to define Joystick Port Names */
if ( numdevs > maxdevs ) numdevs = maxdevs;
for (i=0; i<numdevs; i++) sprintf (SYS_JoyData[i].szDeviceName,"Default Joystick %c",'A'+SYS_JoyData[i].id);
}
}
/* Return the number of devices found */
return(numdevs);
}
/***********************************************************/
/* Function to get the device-dependent name of a joystick */
/***********************************************************/
const char *SDL_SYS_JoystickName(int index)
{
/* No need to verify if device exists, already done in upper layer */
return(SYS_JoyData[index].szDeviceName);
}
/******************************************************************************/
/* Function to open a joystick for use. */
/* The joystick to open is specified by the index field of the joystick. */
/* This should fill the nbuttons and naxes fields of the joystick structure. */
/* It returns 0, or -1 if there is an error. */
/******************************************************************************/
int SDL_SYS_JoystickOpen(SDL_Joystick *joystick)
{
int index; /* Index shortcut for index in joystick structure */
int i; /* Generic Counter */
/* allocate memory for system specific hardware data */
joystick->hwdata = (struct joystick_hwdata *) malloc(sizeof(*joystick->hwdata));
if (joystick->hwdata == NULL)
{
SDL_OutOfMemory();
return(-1);
}
/* Reset Hardware Data */
memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
/* ShortCut Pointer */
index = joystick->index;
/* Define offsets and scales for all axes */
joystick->hwdata->id = SYS_JoyData[index].id;
for ( i = 0; i < MAX_AXES; ++i )
{
if ( (i<2) || i < SYS_JoyData[index].axes )
{
joystick->hwdata->transaxes[i].offset = ((AXIS_MAX + AXIS_MIN)>>1) - SYS_JoyData[index].axes_med[i];
//joystick->hwdata->transaxes[i].scale = (float)((AXIS_MAX - AXIS_MIN)/(SYS_JoyData[index].axes_max[i]-SYS_JoyData[index].axes_min[i]));
joystick->hwdata->transaxes[i].scale1 = (float)abs((AXIS_MIN/SYS_JoyData[index].axes_min[i]));
joystick->hwdata->transaxes[i].scale2 = (float)abs((AXIS_MAX/SYS_JoyData[index].axes_max[i]));
}
else
{
joystick->hwdata->transaxes[i].offset = 0;
//joystick->hwdata->transaxes[i].scale = 1.0; /* Just in case */
joystick->hwdata->transaxes[i].scale1 = 1.0; /* Just in case */
joystick->hwdata->transaxes[i].scale2 = 1.0; /* Just in case */
}
}
/* fill nbuttons, naxes, and nhats fields */
joystick->nbuttons = SYS_JoyData[index].buttons;
joystick->naxes = SYS_JoyData[index].axes;
/* joystick->nhats = SYS_JoyData[index].hats; */
joystick->nhats = 0; /* No support for hats at this time */
/* joystick->nballs = SYS_JoyData[index].balls; */
joystick->nballs = 0; /* No support for balls at this time */
return 0;
}
/***************************************************************************/
/* Function to update the state of a joystick - called as a device poll. */
/* This function shouldn't update the joystick structure directly, */
/* but instead should call SDL_PrivateJoystick*() to deliver events */
/* and update joystick device state. */
/***************************************************************************/
void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
{
APIRET rc; /* Generic OS/2 return code */
int index; /* index shortcurt to joystick index */
int i; /* Generic counter */
int normbut; /* Number of buttons reported by joystick */
int corr; /* Correction for button names */
Sint16 value, change; /* Values used to update axis values */
struct _transaxes *transaxes; /* Shortcut for Correction structure */
Uint32 pos[MAX_AXES]; /* Vector to inform the Axis status */
ULONG ulDataLen; /* Size of data */
GAME_STATUS_STRUCT stGameStatus; /* Joystick Status Structure */
ulDataLen = sizeof(stGameStatus);
rc = DosDevIOCtl(hJoyPort, IOCTL_CAT_USER, GAME_GET_STATUS,
NULL, 0, NULL, &stGameStatus, ulDataLen, &ulDataLen);
if (rc != 0)
{
SDL_SetError("Could not read joystick status.");
return; /* Could not read data */
}
/* Shortcut pointer */
index = joystick->index;
/* joystick motion events */
if (SYS_JoyData[index].id == 0)
{
pos[0] = stGameStatus.curdata.A.x;
pos[1] = stGameStatus.curdata.A.y;
if (SYS_JoyData[index].axes >= 3) pos[2] = stGameStatus.curdata.B.x;
else pos[2]=0;
if (SYS_JoyData[index].axes >= 4) pos[3] = stGameStatus.curdata.B.y;
else pos[3]=0;
pos[4]=0; /* OS/2 basic drivers do not support more than 4 axes joysticks */
pos[5]=0;
}
else if (SYS_JoyData[index].id == 1)
{
pos[0] = stGameStatus.curdata.B.x;
pos[1] = stGameStatus.curdata.B.y;
pos[2]=0;
pos[3]=0;
pos[4]=0;
pos[5]=0;
}
/* Corrects the movements using the callibration */
transaxes = joystick->hwdata->transaxes;
for (i = 0; i < joystick->naxes; i++)
{
value = pos[i] + transaxes[i].offset;
if (value<0)
{
value*=transaxes[i].scale1;
if (value>0) value = AXIS_MIN;
}
else
{
value*=transaxes[i].scale2;
if (value<0) value = AXIS_MAX;
}
change = (value - joystick->axes[i]);
if ( (change < -JOY_AXIS_THRESHOLD) || (change > JOY_AXIS_THRESHOLD) )
{
SDL_PrivateJoystickAxis(joystick, (Uint8)i, (Sint16)value);
}
}
/* joystick button A to D events */
if (SYS_JoyData[index].id == 1) corr = 2;
else corr = 0;
normbut=4; /* Number of normal buttons */
if (joystick->nbuttons<normbut) normbut = joystick->nbuttons;
for ( i = corr; (i-corr) < normbut; ++i )
{
/*
Button A: 1110 0000
Button B: 1101 0000
Button C: 1011 0000
Button D: 0111 0000
*/
if ( (~stGameStatus.curdata.butMask)>>4 & JOY_BUTTON_FLAG(i) )
{
if ( ! joystick->buttons[i-corr] )
{
SDL_PrivateJoystickButton(joystick, (Uint8)(i-corr), SDL_PRESSED);
}
}
else
{
if ( joystick->buttons[i-corr] )
{
SDL_PrivateJoystickButton(joystick, (Uint8)(i-corr), SDL_RELEASED);
}
}
}
/* Joystick button E to H buttons */
/*
Button E: Axis 2 X Left
Button F: Axis 2 Y Up
Button G: Axis 2 X Right
Button H: Axis 2 Y Down
*/
if (joystick->nbuttons>=5)
{
if (stGameStatus.curdata.B.x < SYS_JoyData[index].buttoncalc[0]) SDL_PrivateJoystickButton(joystick, (Uint8)4, SDL_PRESSED);
else SDL_PrivateJoystickButton(joystick, (Uint8)4, SDL_RELEASED);
}
if (joystick->nbuttons>=6)
{
if (stGameStatus.curdata.B.y < SYS_JoyData[index].buttoncalc[1]) SDL_PrivateJoystickButton(joystick, (Uint8)5, SDL_PRESSED);
else SDL_PrivateJoystickButton(joystick, (Uint8)5, SDL_RELEASED);
}
if (joystick->nbuttons>=7)
{
if (stGameStatus.curdata.B.x > SYS_JoyData[index].buttoncalc[2]) SDL_PrivateJoystickButton(joystick, (Uint8)6, SDL_PRESSED);
else SDL_PrivateJoystickButton(joystick, (Uint8)6, SDL_RELEASED);
}
if (joystick->nbuttons>=8)
{
if (stGameStatus.curdata.B.y > SYS_JoyData[index].buttoncalc[3]) SDL_PrivateJoystickButton(joystick, (Uint8)7, SDL_PRESSED);
else SDL_PrivateJoystickButton(joystick, (Uint8)7, SDL_RELEASED);
}
/* joystick hat events */
/* Not Supported under OS/2 */
/* joystick ball events */
/* Not Supported under OS/2 */
}
/******************************************/
/* Function to close a joystick after use */
/******************************************/
void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
{
if (joystick->hwdata != NULL)
{
/* free system specific hardware data */
free(joystick->hwdata);
}
}
/********************************************************************/
/* Function to perform any system-specific joystick related cleanup */
/********************************************************************/
void SDL_SYS_JoystickQuit(void)
{
joyPortClose(&hJoyPort);
}
/************************/
/************************/
/* OS/2 Implementations */
/************************/
/************************/
/*****************************************/
/* Open Joystick Port, if not opened yet */
/*****************************************/
APIRET joyPortOpen(HFILE * hGame)
{
APIRET rc; /* Generic Return Code */
ULONG ulAction; /* ? */
ULONG ulVersion; /* Version of joystick driver */
ULONG ulDataLen; /* Size of version data */
/* Verifies if joyport is not already open... */
if (*hGame != NULL) return 0;
/* Open GAME$ for read */
rc = DosOpen((PSZ)GAMEPDDNAME, hGame, &ulAction, 0, FILE_READONLY,
FILE_OPEN, OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, NULL);
if (rc != 0)
{
SDL_SetError("Could not open Joystick Port.");
return -1;
}
/* Get Joystick Driver Version... must be 2.0 or higher */
ulVersion = 0;
ulDataLen = sizeof(ulVersion);
rc = DosDevIOCtl( *hGame, IOCTL_CAT_USER, GAME_GET_VERSION,
NULL, 0, NULL, &ulVersion, ulDataLen, &ulDataLen);
if (rc != 0)
{
joyPortClose(hGame);
SDL_SetError("Could not get Joystick Driver version.");
return -1;
}
if (ulVersion < GAME_VERSION)
{
joyPortClose(hGame);
SDL_SetError("Driver too old. At least IBM driver version 2.0 required.");
return -1;
}
return 0;
}
/****************************/
/* Close JoyPort, if opened */
/****************************/
void joyPortClose(HFILE * hGame)
{
if (*hGame != NULL) DosClose(*hGame);
*hGame = NULL;
}
/***************************/
/* Get SDL Joystick EnvVar */
/***************************/
int joyGetEnv(struct _joycfg * joydata)
{
char *joyenv; /* Pointer to tested character */
char tempnumber[5]; /* Temporary place to put numeric texts */
joyenv = getenv("SDL_OS2_JOYSTICK");
if (joyenv == NULL) return 0;
/* Joystick Environment is defined! */
while (*joyenv==' ' && *joyenv!=0) joyenv++; /* jump spaces... */
/* If the string name starts with '... get if fully */
if (*joyenv=='\'') joyenv+=joyGetData(++joyenv,joydata->name,'\'',sizeof(joydata->name));
/* If not, get it until the next space */
else if (*joyenv=='\"') joyenv+=joyGetData(++joyenv,joydata->name,'\"',sizeof(joydata->name));
else joyenv+=joyGetData(joyenv,joydata->name,' ',sizeof(joydata->name));
/* Now get the number of axes */
while (*joyenv==' ' && *joyenv!=0) joyenv++; /* jump spaces... */
joyenv+=joyGetData(joyenv,tempnumber,' ',sizeof(tempnumber));
joydata->axes = atoi(tempnumber);
/* Now get the number of buttons */
while (*joyenv==' ' && *joyenv!=0) joyenv++; /* jump spaces... */
joyenv+=joyGetData(joyenv,tempnumber,' ',sizeof(tempnumber));
joydata->buttons = atoi(tempnumber);
/* Now get the number of hats */
while (*joyenv==' ' && *joyenv!=0) joyenv++; /* jump spaces... */
joyenv+=joyGetData(joyenv,tempnumber,' ',sizeof(tempnumber));
joydata->hats = atoi(tempnumber);
/* Now get the number of balls */
while (*joyenv==' ' && *joyenv!=0) joyenv++; /* jump spaces... */
joyenv+=joyGetData(joyenv,tempnumber,' ',sizeof(tempnumber));
joydata->balls = atoi(tempnumber);
return 1;
}
/************************************************************************/
/* Get a text from in the string starting in joyenv until it finds */
/* the stopchar or maxchars is reached. The result is placed in name. */
/************************************************************************/
int joyGetData(char *joyenv, char *name, char stopchar, size_t maxchars)
{
char *nameptr; /* Pointer to the selected character */
int chcnt=0; /* Count how many characters where copied */
nameptr=name;
while (*joyenv!=stopchar && *joyenv!=0)
{
if (nameptr<(name+(maxchars-1)))
{
*nameptr = *joyenv; /* Only copy if smaller than maximum */
nameptr++;
}
chcnt++;
joyenv++;
}
if (*joyenv==stopchar)
{
joyenv++; /* Jump stopchar */
chcnt++;
}
*nameptr = 0; /* Mark last byte */
return chcnt;
}
/*****************************************************************************/
/* */
/* COPYRIGHT Copyright (C) 1995 IBM Corporation */
/* */
/* The following IBM OS/2 source code is provided to you solely for */
/* the purpose of assisting you in your development of OS/2 device */
/* drivers. You may use this code in accordance with the IBM License */
/* Agreement provided in the IBM Device Driver Source Kit for OS/2. This */
/* Copyright statement may not be removed. */
/* */
/*****************************************************************************/
#ifndef JOYOS2_H
#define JOYOS2_H
/****** GAMEPORT.SYS joystick definitions, start *****************************/
#define GAME_VERSION 0x20 /* 2.0 First IBM version */
#define GAMEPDDNAME "GAME$ "
#define IOCTL_CAT_USER 0x80
#define GAME_PORT_GET 0x20 /* read GAMEPORT.SYS values */
#define GAME_PORT_RESET 0x60 /* reset joystick mask with given value */
#pragma pack(1) /* pack structure size is 1 byte */
typedef struct { /* GAMEPORT.SYS structure */
USHORT usJs_AxCnt; /* Joystick_A X position */
USHORT usJs_AyCnt; /* Joystick_A Y position */
USHORT usJs_BxCnt; /* Joystick_B X position */
USHORT usJs_ByCnt; /* Joystick_B Y position */
USHORT usJs_ButtonA1Cnt; /* button A1 press count */
USHORT usJs_ButtonA2Cnt; /* button A2 press count */
USHORT usJs_ButtonB1Cnt; /* button B1 press count */
USHORT usJs_ButtonB2Cnt; /* button B2 press count */
UCHAR ucJs_JoyStickMask; /* mask of connected joystick pots */
UCHAR ucJs_ButtonStatus; /* bits of switches down */
ULONG ulJs_Ticks; /* joystick clock ticks */
} GAME_PORT_STRUCT;
#pragma pack() /*reset to normal pack size */
/****** GAMEPORT.SYS joystick definitions, end *******************************/
/****************************************************************************/
#define GAME_GET_VERSION 0x01
#define GAME_GET_PARMS 0x02
#define GAME_SET_PARMS 0x03
#define GAME_GET_CALIB 0x04
#define GAME_SET_CALIB 0x05
#define GAME_GET_DIGSET 0x06
#define GAME_SET_DIGSET 0x07
#define GAME_GET_STATUS 0x10
#define GAME_GET_STATUS_BUTWAIT 0x11
#define GAME_GET_STATUS_SAMPWAIT 0x12
/****************************************************************************/
/****************************************************************************/
// bit masks for each axis
#define JOY_AX_BIT 0x01
#define JOY_AY_BIT 0x02
#define JOY_A_BITS (JOY_AX_BIT|JOY_AY_BIT)
#define JOY_BX_BIT 0x04
#define JOY_BY_BIT 0x08
#define JOY_B_BITS (JOY_BX_BIT|JOY_BY_BIT)
#define JOY_ALLPOS_BITS (JOY_A_BITS|JOY_B_BITS)
// bit masks for each button
#define JOY_BUT1_BIT 0x10
#define JOY_BUT2_BIT 0x20
#define JOY_BUT3_BIT 0x40
#define JOY_BUT4_BIT 0x80
#define JOY_ALL_BUTS (JOY_BUT1_BIT|JOY_BUT2_BIT|JOY_BUT3_BIT|JOY_BUT4_BIT)
/****************************************************************************/
/****************************************************************************/
// 1-D position struct used for each axis
typedef SHORT GAME_POS; /* some data formats require signed values */
// simple 2-D position for each joystick
typedef struct
{
GAME_POS x;
GAME_POS y;
}
GAME_2DPOS_STRUCT;
// struct defining the instantaneous state of both sticks and all buttons
typedef struct
{
GAME_2DPOS_STRUCT A;
GAME_2DPOS_STRUCT B;
USHORT butMask;
}
GAME_DATA_STRUCT;
// struct to be used for calibration and digital response on each axis
typedef struct
{
GAME_POS lower;
GAME_POS centre;
GAME_POS upper;
}
GAME_3POS_STRUCT;
/****************************************************************************/
/****************************************************************************/
// status struct returned to OS/2 applications:
// current data for all sticks as well as button counts since last read
typedef struct
{
GAME_DATA_STRUCT curdata;
USHORT b1cnt;
USHORT b2cnt;
USHORT b3cnt;
USHORT b4cnt;
}
GAME_STATUS_STRUCT;
/****************************************************************************/
/****************************************************************************/
/* in use bitmasks originating in 0.2b */
#define GAME_USE_BOTH_OLDMASK 0x01 /* for backward compat with bool */
#define GAME_USE_X_NEWMASK 0x02
#define GAME_USE_Y_NEWMASK 0x04
#define GAME_USE_X_EITHERMASK (GAME_USE_X_NEWMASK|GAME_USE_BOTH_OLDMASK)
#define GAME_USE_Y_EITHERMASK (GAME_USE_Y_NEWMASK|GAME_USE_BOTH_OLDMASK)
#define GAME_USE_BOTH_NEWMASK (GAME_USE_X_NEWMASK|GAME_USE_Y_NEWMASK)
/* only timed sampling implemented in version 1.0 */
#define GAME_MODE_TIMED 1 /* timed sampling */
#define GAME_MODE_REQUEST 2 /* request driven sampling */
/* only raw implemented in version 1.0 */
#define GAME_DATA_FORMAT_RAW 1 /* [l,c,r] */
#define GAME_DATA_FORMAT_SIGNED 2 /* [-l,0,+r] */
#define GAME_DATA_FORMAT_BINARY 3 /* {-1,0,+1} */
#define GAME_DATA_FORMAT_SCALED 4 /* [-10,+10] */
// parameters defining the operation of the driver
typedef struct
{
USHORT useA; /* new bitmasks: see above */
USHORT useB;
USHORT mode; /* see consts above */
USHORT format; /* see consts above */
USHORT sampDiv; /* samp freq = 32 / n */
USHORT scale; /* scaling factor */
USHORT res1; /* must be 0 */
USHORT res2; /* must be 0 */
}
GAME_PARM_STRUCT;
/****************************************************************************/
/****************************************************************************/
// calibration values for each axis:
// - upper limit on value to be considered in lower range
// - centre value
// - lower limit on value to be considered in upper range
typedef struct
{
GAME_3POS_STRUCT Ax;
GAME_3POS_STRUCT Ay;
GAME_3POS_STRUCT Bx;
GAME_3POS_STRUCT By;
}
GAME_CALIB_STRUCT;
/****************************************************************************/
/****************************************************************************/
// struct defining the digital response values for all axes
typedef struct
{
GAME_3POS_STRUCT Ax;
GAME_3POS_STRUCT Ay;
GAME_3POS_STRUCT Bx;
GAME_3POS_STRUCT By;
}
GAME_DIGSET_STRUCT;
/****************************************************************************/
#endif
......@@ -781,6 +781,7 @@ static struct dlstatus *loadModule(const char *path, const struct stat *sbuf, in
const char *errstr;
const char *file;
void (*init) (void);
ofirc = NSCreateObjectFileImageFromFile(path, &ofi);
switch (ofirc)
{
......
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2004 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
/* System dependent library loading routines */
#if !SDL_INTERNAL_BUILDING_LOADSO
#error Do not compile directly...compile src/SDL_loadso.c instead!
#endif
#if !defined(__OS2__)
#error Compiling for the wrong platform?
#endif
#include <stdio.h>
#define INCL_DOSERRORS
#define INCL_DOSMODULEMGR
#include <os2.h>
#include "SDL_types.h"
#include "SDL_error.h"
#include "SDL_loadso.h"
void *SDL_LoadObject(const char *sofile)
{
HMODULE handle = NULL;
char buf[512];
APIRET ulrc = DosLoadModule(buf, sizeof (buf), (char *) sofile, &handle);
/* Generate an error message if all loads failed */
if ((ulrc != NO_ERROR) || (handle == NULL))
SDL_SetError("Failed loading %s: %s", sofile, buf);
return((void *) handle);
}
void *SDL_LoadFunction(void *handle, const char *name)
{
const char *loaderror = "Unknown error";
void *symbol = NULL;
APIRET ulrc = DosQueryProcAddr((HMODULE)handle, 0, (char *)name, &symbol);
if (ulrc == ERROR_INVALID_HANDLE)
loaderror = "Invalid module handle";
else if (ulrc == ERROR_INVALID_NAME)
loaderror = "Symbol not found";
if (symbol == NULL)
SDL_SetError("Failed loading %s: %s", name, loaderror);
return(symbol);
}
void SDL_UnloadObject(void *handle)
{
if ( handle != NULL )
DosFreeModule((HMODULE) handle);
}
#=============================================================================
# This is a Watcom makefile to build SDL.DLL for OS/2
#
# Makefile for threading
#=============================================================================
object_files=SDL_thread.obj SDL_sysmutex.obj SDL_syssem.obj SDL_systhread.obj SDL_syscond.obj
ExtraCFlags=
#
#==============================================================================
#
!include ..\..\Watcom.mif
.before
set include=$(%os2tk)\h;$(%include);../../include;./os2;../;
all : $(object_files)
SDL_sysmutex.obj: .AUTODEPEND
wcc386 os2\SDL_sysmutex.c $(cflags)
SDL_syssem.obj: .AUTODEPEND
wcc386 os2\SDL_syssem.c $(cflags)
SDL_systhread.obj: .AUTODEPEND
wcc386 os2\SDL_systhread.c $(cflags)
SDL_syscond.obj: .AUTODEPEND
wcc386 os2\SDL_syscond.c $(cflags)
clean : .SYMBOLIC
@if exist *.obj del *.obj
@if exist *.map del *.map
@if exist *.res del *.res
@if exist *.lst del *.lst
......@@ -33,7 +33,11 @@ static char rcsid =
saves a system-dependent thread id in thread->id, and returns 0
on success.
*/
#ifdef __OS2__
extern int SDL_SYS_CreateThread(SDL_Thread *thread, void *args, pfnSDL_CurrentBeginThread pfnBeginThread, pfnSDL_CurrentEndThread pfnEndThread);
#else
extern int SDL_SYS_CreateThread(SDL_Thread *thread, void *args);
#endif
/* This function does any necessary setup in the child thread */
extern void SDL_SYS_SetupThread(void);
......
......@@ -218,7 +218,11 @@ void SDL_RunThread(void *data)
*statusloc = userfunc(userdata);
}
SDL_Thread *SDL_CreateThread(int (*fn)(void *), void *data)
#ifdef __OS2__
DECLSPEC SDL_Thread * SDLCALL SDL_CreateThread_Core(int (*fn)(void *), void *data, pfnSDL_CurrentBeginThread pfnBeginThread, pfnSDL_CurrentEndThread pfnEndThread)
#else
DECLSPEC SDL_Thread * SDLCALL SDL_CreateThread(int (*fn)(void *), void *data)
#endif
{
SDL_Thread *thread;
thread_args *args;
......@@ -254,7 +258,11 @@ SDL_Thread *SDL_CreateThread(int (*fn)(void *), void *data)
SDL_AddThread(thread);
/* Create the thread and go! */
#ifdef __OS2__
ret = SDL_SYS_CreateThread(thread, args, pfnBeginThread, pfnEndThread);
#else
ret = SDL_SYS_CreateThread(thread, args);
#endif
if ( ret >= 0 ) {
/* Wait for the thread function to use arguments */
SDL_SemWait(args->wait);
......
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif
/* An implementation of condition variables using semaphores and mutexes */
/*
This implementation borrows heavily from the BeOS condition variable
implementation, written by Christopher Tate and Owen Smith. Thanks!
*/
#include <stdio.h>
#include <stdlib.h>
#include "SDL_error.h"
#include "SDL_thread.h"
struct SDL_cond
{
SDL_mutex *lock;
int waiting;
int signals;
SDL_sem *wait_sem;
SDL_sem *wait_done;
};
/* Create a condition variable */
DECLSPEC SDL_cond * SDLCALL SDL_CreateCond(void)
{
SDL_cond *cond;
cond = (SDL_cond *) malloc(sizeof(SDL_cond));
if ( cond ) {
cond->lock = SDL_CreateMutex();
cond->wait_sem = SDL_CreateSemaphore(0);
cond->wait_done = SDL_CreateSemaphore(0);
cond->waiting = cond->signals = 0;
if ( ! cond->lock || ! cond->wait_sem || ! cond->wait_done ) {
SDL_DestroyCond(cond);
cond = NULL;
}
} else {
SDL_OutOfMemory();
}
return(cond);
}
/* Destroy a condition variable */
DECLSPEC void SDLCALL SDL_DestroyCond(SDL_cond *cond)
{
if ( cond ) {
if ( cond->wait_sem ) {
SDL_DestroySemaphore(cond->wait_sem);
}
if ( cond->wait_done ) {
SDL_DestroySemaphore(cond->wait_done);
}
if ( cond->lock ) {
SDL_DestroyMutex(cond->lock);
}
free(cond);
}
}
/* Restart one of the threads that are waiting on the condition variable */
DECLSPEC int SDLCALL SDL_CondSignal(SDL_cond *cond)
{
if ( ! cond ) {
SDL_SetError("Passed a NULL condition variable");
return -1;
}
/* If there are waiting threads not already signalled, then
signal the condition and wait for the thread to respond.
*/
SDL_LockMutex(cond->lock);
if ( cond->waiting > cond->signals ) {
++cond->signals;
SDL_SemPost(cond->wait_sem);
SDL_UnlockMutex(cond->lock);
SDL_SemWait(cond->wait_done);
} else {
SDL_UnlockMutex(cond->lock);
}
return 0;
}
/* Restart all threads that are waiting on the condition variable */
DECLSPEC int SDLCALL SDL_CondBroadcast(SDL_cond *cond)
{
if ( ! cond ) {
SDL_SetError("Passed a NULL condition variable");
return -1;
}
/* If there are waiting threads not already signalled, then
signal the condition and wait for the thread to respond.
*/
SDL_LockMutex(cond->lock);
if ( cond->waiting > cond->signals ) {
int i, num_waiting;
num_waiting = (cond->waiting - cond->signals);
cond->signals = cond->waiting;
for ( i=0; i<num_waiting; ++i ) {
SDL_SemPost(cond->wait_sem);
}
/* Now all released threads are blocked here, waiting for us.
Collect them all (and win fabulous prizes!) :-)
*/
SDL_UnlockMutex(cond->lock);
for ( i=0; i<num_waiting; ++i ) {
SDL_SemWait(cond->wait_done);
}
} else {
SDL_UnlockMutex(cond->lock);
}
return 0;
}
/* Wait on the condition variable for at most 'ms' milliseconds.
The mutex must be locked before entering this function!
The mutex is unlocked during the wait, and locked again after the wait.
Typical use:
Thread A:
SDL_LockMutex(lock);
while ( ! condition ) {
SDL_CondWait(cond);
}
SDL_UnlockMutex(lock);
Thread B:
SDL_LockMutex(lock);
...
condition = true;
...
SDL_UnlockMutex(lock);
*/
DECLSPEC int SDLCALL SDL_CondWaitTimeout(SDL_cond *cond, SDL_mutex *mutex, Uint32 ms)
{
int retval;
if ( ! cond ) {
SDL_SetError("Passed a NULL condition variable");
return -1;
}
/* Obtain the protection mutex, and increment the number of waiters.
This allows the signal mechanism to only perform a signal if there
are waiting threads.
*/
SDL_LockMutex(cond->lock);
++cond->waiting;
SDL_UnlockMutex(cond->lock);
/* Unlock the mutex, as is required by condition variable semantics */
SDL_UnlockMutex(mutex);
/* Wait for a signal */
if ( ms == SDL_MUTEX_MAXWAIT ) {
retval = SDL_SemWait(cond->wait_sem);
} else {
retval = SDL_SemWaitTimeout(cond->wait_sem, ms);
}
/* Let the signaler know we have completed the wait, otherwise
the signaler can race ahead and get the condition semaphore
if we are stopped between the mutex unlock and semaphore wait,
giving a deadlock. See the following URL for details:
http://www-classic.be.com/aboutbe/benewsletter/volume_III/Issue40.html
*/
SDL_LockMutex(cond->lock);
if ( cond->signals > 0 ) {
/* If we timed out, we need to eat a condition signal */
if ( retval > 0 ) {
SDL_SemWait(cond->wait_sem);
}
/* We always notify the signal thread that we are done */
SDL_SemPost(cond->wait_done);
/* Signal handshake complete */
--cond->signals;
}
--cond->waiting;
SDL_UnlockMutex(cond->lock);
/* Lock the mutex, as is required by condition variable semantics */
SDL_LockMutex(mutex);
return retval;
}
/* Wait on the condition variable forever */
DECLSPEC int SDLCALL SDL_CondWait(SDL_cond *cond, SDL_mutex *mutex)
{
return SDL_CondWaitTimeout(cond, mutex, SDL_MUTEX_MAXWAIT);
}
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif
/* Mutex functions using the OS/2 API */
#include <stdio.h>
#include <stdlib.h>
#define INCL_DOSERRORS
#define INCL_DOSSEMAPHORES
#include <os2.h>
#include "SDL_error.h"
#include "SDL_mutex.h"
struct SDL_mutex {
HMTX hmtxID;
};
/* Create a mutex */
DECLSPEC SDL_mutex * SDLCALL SDL_CreateMutex(void)
{
SDL_mutex *mutex;
APIRET ulrc;
/* Allocate mutex memory */
mutex = (SDL_mutex *)malloc(sizeof(*mutex));
if (mutex)
{
/* Create the mutex, with initial value signaled */
ulrc = DosCreateMutexSem(NULL, // Create unnamed semaphore
&(mutex->hmtxID), // Pointer to handle
0L, // Flags: create it private (not shared)
FALSE); // Initial value: unowned
if (ulrc!=NO_ERROR)
{
SDL_SetError("Couldn't create mutex");
free(mutex);
mutex = NULL;
}
} else {
SDL_OutOfMemory();
}
return(mutex);
}
/* Free the mutex */
DECLSPEC void SDLCALL SDL_DestroyMutex(SDL_mutex *mutex)
{
if ( mutex )
{
if ( mutex->hmtxID )
{
DosCloseMutexSem(mutex->hmtxID);
mutex->hmtxID = 0;
}
free(mutex);
}
}
/* Lock the mutex */
DECLSPEC int SDLCALL SDL_mutexP(SDL_mutex *mutex)
{
if ( mutex == NULL )
{
SDL_SetError("Passed a NULL mutex");
return -1;
}
if ( DosRequestMutexSem(mutex->hmtxID, SEM_INDEFINITE_WAIT) != NO_ERROR )
{
SDL_SetError("Couldn't wait on mutex");
return -1;
}
return(0);
}
/* Unlock the mutex */
DECLSPEC int SDLCALL SDL_mutexV(SDL_mutex *mutex)
{
if ( mutex == NULL )
{
SDL_SetError("Passed a NULL mutex");
return -1;
}
if ( DosReleaseMutexSem(mutex->hmtxID) != NO_ERROR )
{
SDL_SetError("Couldn't release mutex");
return -1;
}
return(0);
}
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif
/* Semaphore functions using the OS/2 API */
#include <stdio.h>
#include <stdlib.h>
#define INCL_DOS
#define INCL_DOSERRORS
#define INCL_DOSSEMAPHORES
#include <os2.h>
#include "SDL_error.h"
#include "SDL_thread.h"
#include "SDL_timer.h"
struct SDL_semaphore {
HMTX id;
HEV changed;
Uint32 value;
};
/* Create a semaphore */
DECLSPEC SDL_sem * SDLCALL SDL_CreateSemaphore(Uint32 initial_value)
{
SDL_sem *sem;
ULONG ulrc;
/* Allocate sem memory */
sem = (SDL_sem *)malloc(sizeof(*sem));
if ( sem ) {
/* Create the mutex semaphore */
ulrc = DosCreateMutexSem(NULL,&(sem->id),0,TRUE);
if ( ulrc ) {
SDL_SetError("Couldn't create semaphore");
free(sem);
sem = NULL;
} else
{
DosCreateEventSem(NULL, &(sem->changed), 0, FALSE);
sem->value = initial_value;
DosReleaseMutexSem(sem->id);
}
} else {
SDL_OutOfMemory();
}
return(sem);
}
/* Free the semaphore */
DECLSPEC void SDLCALL SDL_DestroySemaphore(SDL_sem *sem)
{
if ( sem ) {
if ( sem->id ) {
DosCloseEventSem(sem->changed);
DosCloseMutexSem(sem->id);
sem->id = 0;
}
free(sem);
}
}
DECLSPEC int SDLCALL SDL_SemWaitTimeout(SDL_sem *sem, Uint32 timeout)
{
ULONG ulrc;
if ( ! sem ) {
SDL_SetError("Passed a NULL sem");
return -1;
}
if ( timeout == SDL_MUTEX_MAXWAIT ) {
while (1) {
ulrc = DosRequestMutexSem(sem->id, SEM_INDEFINITE_WAIT);
if (ulrc) {
/* if error waiting mutex */
SDL_SetError("DosRequestMutexSem() failed");
return -1;
} else if (sem->value) {
sem->value--;
DosReleaseMutexSem(sem->id);
return 0;
} else {
ULONG ulPostCount;
DosResetEventSem(sem->changed, &ulPostCount);
DosReleaseMutexSem(sem->id);
/* continue waiting until somebody posts the semaphore */
DosWaitEventSem(sem->changed, SEM_INDEFINITE_WAIT);
}
}
} else
if ( timeout == 0 )
{
ulrc = DosRequestMutexSem(sem->id, SEM_INDEFINITE_WAIT);
if (ulrc==NO_ERROR)
{
if (sem->value)
{
sem->value--;
DosReleaseMutexSem(sem->id);
return 0;
} else
{
DosReleaseMutexSem(sem->id);
return SDL_MUTEX_TIMEDOUT;
}
} else
{
SDL_SetError("DosRequestMutexSem() failed");
return -1;
}
} else {
ulrc = DosRequestMutexSem(sem->id, SEM_INDEFINITE_WAIT);
if (ulrc) {
/* if error waiting mutex */
SDL_SetError("DosRequestMutexSem() failed");
return -1;
} else
if (sem->value) {
sem->value--;
DosReleaseMutexSem(sem->id);
return 0;
} else {
ULONG ulPostCount;
DosResetEventSem(sem->changed, &ulPostCount);
DosReleaseMutexSem(sem->id);
/* continue waiting until somebody posts the semaphore */
ulrc = DosWaitEventSem(sem->changed, timeout);
if (ulrc==NO_ERROR)
return 0;
else
return SDL_MUTEX_TIMEDOUT;
}
}
/* never reached */
return -1;
}
DECLSPEC int SDLCALL SDL_SemTryWait(SDL_sem *sem)
{
return SDL_SemWaitTimeout(sem, 0);
}
DECLSPEC int SDLCALL SDL_SemWait(SDL_sem *sem)
{
return SDL_SemWaitTimeout(sem, SDL_MUTEX_MAXWAIT);
}
/* Returns the current count of the semaphore */
DECLSPEC Uint32 SDLCALL SDL_SemValue(SDL_sem *sem)
{
if ( ! sem ) {
SDL_SetError("Passed a NULL sem");
return 0;
}
return sem->value;
}
DECLSPEC int SDLCALL SDL_SemPost(SDL_sem *sem)
{
if ( ! sem ) {
SDL_SetError("Passed a NULL sem");
return -1;
}
if ( DosRequestMutexSem(sem->id,SEM_INDEFINITE_WAIT) ) {
SDL_SetError("DosRequestMutexSem() failed");
return -1;
}
sem->value++;
DosPostEventSem(sem->changed);
DosReleaseMutexSem(sem->id);
return 0;
}
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif
/* OS/2 thread management routines for SDL */
#include <stdio.h>
#include <stdlib.h>
#include <process.h>
#define INCL_DOSERRORS
#define INCL_DOSPROCESS
#include <os2.h>
#include "SDL_error.h"
#include "SDL_thread.h"
#include "SDL_systhread.h"
typedef struct ThreadStartParms
{
void *args;
pfnSDL_CurrentEndThread pfnCurrentEndThread;
} tThreadStartParms, *pThreadStartParms;
static void threadfunc(void *pparm)
{
pThreadStartParms pThreadParms = pparm;
pfnSDL_CurrentEndThread pfnCurrentEndThread = NULL;
// Call the thread function!
SDL_RunThread(pThreadParms->args);
// Get the current endthread we have to use!
if (pThreadParms)
{
pfnCurrentEndThread = pThreadParms->pfnCurrentEndThread;
free(pThreadParms);
}
// Call endthread!
if (pfnCurrentEndThread)
(*pfnCurrentEndThread)();
}
int SDL_SYS_CreateThread(SDL_Thread *thread, void *args, pfnSDL_CurrentBeginThread pfnBeginThread, pfnSDL_CurrentEndThread pfnEndThread)
{
pThreadStartParms pThreadParms = malloc(sizeof(tThreadStartParms));
if (!pThreadParms)
{
SDL_SetError("Not enough memory to create thread");
return(-1);
}
// 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->threadid = thread->handle = (*pfnBeginThread)(threadfunc, 512*1024, pThreadParms);
if (thread->threadid<=0)
{
SDL_SetError("Not enough resources to create thread");
return(-1);
}
return(0);
}
void SDL_SYS_SetupThread(void)
{
return;
}
DECLSPEC Uint32 SDLCALL SDL_ThreadID(void)
{
PTIB tib;
DosGetInfoBlocks(&tib, NULL);
return((Uint32) (tib->tib_ptib2->tib2_ultid));
}
void SDL_SYS_WaitThread(SDL_Thread *thread)
{
TID tid = thread->handle;
DosWaitThread(&tid, DCWW_WAIT);
}
/* WARNING: This function is really a last resort.
* Threads should be signaled and then exit by themselves.
* TerminateThread() doesn't perform stack and DLL cleanup.
*/
void SDL_SYS_KillThread(SDL_Thread *thread)
{
DosKillThread(thread->handle);
}
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#define INCL_DOSPROCESS
#include <os2.h>
typedef TID SYS_ThreadHandle;
#=============================================================================
# This is a Watcom makefile to build SDL.DLL for OS/2
#
# Makefile for timers
#=============================================================================
object_files=SDL_timer.obj SDL_systimer.obj
ExtraCFlags=
#
#==============================================================================
#
!include ..\..\Watcom.mif
.before
set include=$(%os2tk)\h;$(%include);../../include;./os2;../;
all : $(object_files)
SDL_systimer.obj: .AUTODEPEND
wcc386 os2\SDL_systimer.c $(cflags)
clean : .SYMBOLIC
@if exist *.obj del *.obj
@if exist *.map del *.map
@if exist *.res del *.res
@if exist *.lst del *.lst
......@@ -242,7 +242,7 @@ SDL_bool SDL_RemoveTimer(SDL_TimerID id)
}
/* Old style callback functions are wrapped through this */
static Uint32 callback_wrapper(Uint32 ms, void *param)
static Uint32 SDLCALL callback_wrapper(Uint32 ms, void *param)
{
SDL_TimerCallback func = (SDL_TimerCallback) param;
return (*func)(ms);
......
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif
#define INCL_DOSMISC
#define INCL_DOSERRORS
#define INCL_DOSSEMAPHORES
#define INCL_DOSDATETIME
#define INCL_DOSPROCESS
#define INCL_DOSPROFILE
#define INCL_DOSEXCEPTIONS
#include <os2.h>
#include "SDL_thread.h"
#include "SDL_timer.h"
#include "SDL_timer_c.h"
#include "SDL_error.h"
#define TIME_WRAP_VALUE (~(DWORD)0)
/* The first high-resolution ticks value of the application */
static long long hires_start_ticks;
/* The number of ticks per second of the high-resolution performance counter */
static ULONG hires_ticks_per_second;
void SDL_StartTicks(void)
{
DosTmrQueryFreq(&hires_ticks_per_second);
DosTmrQueryTime((PQWORD)&hires_start_ticks);
}
DECLSPEC Uint32 SDLCALL SDL_GetTicks(void)
{
long long hires_now;
ULONG ticks = ticks;
DosTmrQueryTime((PQWORD)&hires_now);
/*
hires_now -= hires_start_ticks;
hires_now *= 1000;
hires_now /= hires_ticks_per_second;
*/
/* inline asm to avoid runtime inclusion */
_asm {
push edx
push eax
mov eax, dword ptr hires_now
mov edx, dword ptr hires_now+4
sub eax, dword ptr hires_start_ticks
sbb edx, dword ptr hires_start_ticks+4
mov ebx,1000
mov ecx,edx
mul ebx
push eax
push edx
mov eax,ecx
mul ebx
pop eax
add edx,eax
pop eax
mov ebx, dword ptr hires_ticks_per_second
div ebx
mov dword ptr ticks, eax
pop edx
pop eax
}
return ticks;
}
/* High resolution sleep, originally made by Ilya Zakharevich */
DECLSPEC void SDLCALL SDL_Delay(Uint32 ms)
{
/* This is similar to DosSleep(), but has 8ms granularity in time-critical
threads even on Warp3. */
HEV hevEvent1 = 0; /* Event semaphore handle */
HTIMER htimerEvent1 = 0; /* Timer handle */
APIRET rc = NO_ERROR; /* Return code */
int ret = 1;
ULONG priority = 0, nesting; /* Shut down the warnings */
PPIB pib;
PTIB tib;
char *e = NULL;
APIRET badrc;
int switch_priority = 50;
DosCreateEventSem(NULL, /* Unnamed */
&hevEvent1, /* Handle of semaphore returned */
DC_SEM_SHARED, /* Shared needed for DosAsyncTimer */
FALSE); /* Semaphore is in RESET state */
if (ms >= switch_priority)
switch_priority = 0;
if (switch_priority)
{
if (DosGetInfoBlocks(&tib, &pib)!=NO_ERROR)
switch_priority = 0;
else
{
/* In Warp3, to switch scheduling to 8ms step, one needs to do
DosAsyncTimer() in time-critical thread. On laters versions,
more and more cases of wait-for-something are covered.
It turns out that on Warp3fp42 it is the priority at the time
of DosAsyncTimer() which matters. Let's hope that this works
with later versions too... XXXX
*/
priority = (tib->tib_ptib2->tib2_ulpri);
if ((priority & 0xFF00) == 0x0300) /* already time-critical */
switch_priority = 0;
/* Make us time-critical. Just modifying TIB is not enough... */
/* tib->tib_ptib2->tib2_ulpri = 0x0300;*/
/* We do not want to run at high priority if a signal causes us
to longjmp() out of this section... */
if (DosEnterMustComplete(&nesting))
switch_priority = 0;
else
DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
}
}
if ((badrc = DosAsyncTimer(ms,
(HSEM) hevEvent1, /* Semaphore to post */
&htimerEvent1))) /* Timer handler (returned) */
e = "DosAsyncTimer";
if (switch_priority && tib->tib_ptib2->tib2_ulpri == 0x0300)
{
/* Nobody switched priority while we slept... Ignore errors... */
/* tib->tib_ptib2->tib2_ulpri = priority; */ /* Get back... */
if (!(rc = DosSetPriority(PRTYS_THREAD, (priority>>8) & 0xFF, 0, 0)))
rc = DosSetPriority(PRTYS_THREAD, 0, priority & 0xFF, 0);
}
if (switch_priority)
rc = DosExitMustComplete(&nesting); /* Ignore errors */
/* The actual blocking call is made with "normal" priority. This way we
should not bother with DosSleep(0) etc. to compensate for us interrupting
higher-priority threads. The goal is to prohibit the system spending too
much time halt()ing, not to run us "no matter what". */
if (!e) /* Wait for AsyncTimer event */
badrc = DosWaitEventSem(hevEvent1, SEM_INDEFINITE_WAIT);
if (e) ; /* Do nothing */
else if (badrc == ERROR_INTERRUPT)
ret = 0;
else if (badrc)
e = "DosWaitEventSem";
if ((rc = DosCloseEventSem(hevEvent1)) && !e) { /* Get rid of semaphore */
e = "DosCloseEventSem";
badrc = rc;
}
if (e)
{
SDL_SetError("[SDL_Delay] : Had error in %s(), rc is 0x%x\n", e, badrc);
}
}
/* Data to handle a single periodic alarm */
static int timer_alive = 0;
static SDL_Thread *timer = NULL;
static int RunTimer(void *unused)
{
DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
while ( timer_alive ) {
if ( SDL_timer_running ) {
SDL_ThreadedTimerCheck();
}
SDL_Delay(10);
}
return(0);
}
/* This is only called if the event thread is not running */
int SDL_SYS_TimerInit(void)
{
timer_alive = 1;
timer = SDL_CreateThread(RunTimer, NULL);
if ( timer == NULL )
return(-1);
return(SDL_SetTimerThreaded(1));
}
void SDL_SYS_TimerQuit(void)
{
timer_alive = 0;
if ( timer ) {
SDL_WaitThread(timer, NULL);
timer = NULL;
}
}
int SDL_SYS_StartTimer(void)
{
SDL_SetError("Internal logic error: OS/2 uses threaded timer");
return(-1);
}
void SDL_SYS_StopTimer(void)
{
return;
}
#=============================================================================
# This is a Watcom makefile to build SDL.DLL for OS/2
#
# Makefile for threading
#=============================================================================
object_files=SDL_blit.obj SDL_blit_0.obj SDL_blit_1.obj SDL_blit_A.obj SDL_blit_N.obj SDL_bmp.obj SDL_cursor.obj SDL_gamma.obj SDL_pixels.obj SDL_RLEaccel.obj SDL_stretch.obj SDL_surface.obj SDL_video.obj SDL_yuv.obj SDL_yuv_mmx.obj SDL_yuv_sw.obj SDL_os2fslib.obj
ExtraCFlags=-dUSE_DOSSETPRIORITY
#
#==============================================================================
#
!include ..\..\Watcom.mif
.before
set include=$(%os2tk)\h;$(%include);../../include;../;./os2;../events;../hermes;$(%FSLIB);
all : $(object_files)
SDL_os2fslib.obj : .AUTODEPEND
wcc386 os2fslib\SDL_os2fslib.c $(cflags)
clean : .SYMBOLIC
@if exist *.obj del *.obj
@if exist *.map del *.map
@if exist *.res del *.res
@if exist *.lst del *.lst
......@@ -423,6 +423,9 @@ extern VideoBootStrap DC_bootstrap;
#ifdef ENABLE_RISCOS
extern VideoBootStrap RISCOS_bootstrap;
#endif
#ifdef __OS2__
extern VideoBootStrap OS2FSLib_bootstrap;
#endif
/* This is the current video device */
extern SDL_VideoDevice *current_video;
......
......@@ -126,6 +126,9 @@ static VideoBootStrap *bootstrap[] = {
#ifdef ENABLE_RISCOS
&RISCOS_bootstrap,
#endif
#ifdef __OS2__
&OS2FSLib_bootstrap,
#endif
#ifdef ENABLE_DUMMYVIDEO
&DUMMY_bootstrap,
#endif
......@@ -664,7 +667,10 @@ SDL_Surface * SDL_SetVideoMode (int width, int height, int bpp, Uint32 flags)
SDL_VideoSurface = NULL; /* In case it's freed by driver */
mode = video->SetVideoMode(this, prev_mode,video_w,video_h,video_bpp,flags);
if ( mode ) { /* Prevent resize events from mode change */
/* But not on OS/2 */
#ifndef __OS2__
SDL_PrivateResize(mode->w, mode->h);
#endif
/* Sam - If we asked for OpenGL mode, and didn't get it, fail */
if ( is_opengl && !(mode->flags & SDL_OPENGL) ) {
......
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997-2004 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <process.h>
#include <time.h>
#include "SDL.h"
#include "SDL_error.h"
#include "SDL_video.h"
#include "SDL_mouse.h"
#include "SDL_sysvideo.h"
#include "SDL_pixels_c.h"
#include "SDL_events_c.h"
#include "SDL_os2fslib.h"
static ULONG ulFCFToUse =
FCF_TITLEBAR |
FCF_SYSMENU |
FCF_MINBUTTON |
FCF_MAXBUTTON |
FCF_NOBYTEALIGN |
FCF_SIZEBORDER |
FCF_TASKLIST;
static int bMouseCaptured = 0;
static int bMouseCapturable = 0;
static HPOINTER hptrGlobalPointer = NULL;
static HPOINTER hptrCurrentIcon = NULL;
static int iWindowSizeX = 320;
static int iWindowSizeY = 200;
static int bWindowResized = 0;
#pragma pack(1)
typedef struct BMPINFO
{
BITMAPINFO;
RGB clr;
} BMPINFO, *PBMPINFO;
#pragma pack()
// Backdoors:
DECLSPEC void SDLCALL SDL_OS2FSLIB_SetFCFToUse(ULONG ulFCF)
{
ulFCFToUse = ulFCF;
}
// Configuration defines:
// We have to report empty alpha mask, otherwise SDL will select
// alpha blitters, and this will have unwanted results, as we don't
// support alpha channel in FSLib yet.
#define REPORT_EMPTY_ALPHA_MASK
// Experimental: Move every FSLib_BitBlt() call into window message
// processing function.
// This may fix dirt left on desktop. Or not.
//#define BITBLT_IN_WINMESSAGEPROC
// Experimental-2: Use WinLockWindowUpdate() in around bitblts!
// This is not enabled, because it seems to cause more problems
// than good.
//#define USE_WINLOCKWINDOWUPDATE_AROUND_BITBLTS
// Use the following to show resized image instead of black stuff
// even if the surface is resizable.
//#define RESIZE_EVEN_IF_RESIZABLE
/* The translation table from a VK keysym to a SDL keysym */
static SDLKey HWScanKeyMap[256];
static SDL_keysym *TranslateKey(int vkey, int chcode, int scancode, SDL_keysym *keysym, int iPressed);
static int iShiftIsPressed;
#ifdef BITBLT_IN_WINMESSAGEPROC
#define WM_UPDATERECTSREQUEST WM_USER+50
#endif
#ifdef USE_WINLOCKWINDOWUPDATE_AROUND_BITBLTS
#define FSLIB_BITBLT(hwnd, buffer, top, left, width, height) \
{ \
WinLockWindowUpdate(HWND_DESKTOP, HWND_DESKTOP); \
FSLib_BitBlt(hwnd, buffer, top, left, width, height); \
WinLockWindowUpdate(HWND_DESKTOP, NULL); \
}
#else
#define FSLIB_BITBLT(hwnd, buffer, top, left, width, height) \
FSLib_BitBlt(hwnd, buffer, top, left, width, height);
#endif
/////////////////////////////////////////////////////////////////////
//
// SetAccessableWindowPos
//
// Same as WinSetWindowPos(), but takes care for the window to be
// always on the screen, the titlebar will be accessable everytime.
//
/////////////////////////////////////////////////////////////////////
static BOOL SetAccessableWindowPos(HWND hwnd, HWND hwndInsertBehind,
LONG x, LONG y,
LONG cx, LONG cy,
ULONG fl)
{
SWP swpDesktop, swp;
// Get desktop area
WinQueryWindowPos(HWND_DESKTOP, &swpDesktop);
if ((fl & SWP_MOVE) && (fl & SWP_SIZE))
{
// If both moving and sizing, then change size and pos now!!
if (x+cx>swpDesktop.cx)
x = swpDesktop.cx - cx;
if (x<0)
x = 0;
if (y<0)
y = 0;
if (y+cy>swpDesktop.cy)
y = swpDesktop.cy - cy;
return WinSetWindowPos(hwnd, hwndInsertBehind, x, y, cx, cy, fl);
} else
if (fl & SWP_MOVE)
{
// Just moving
WinQueryWindowPos(hwnd, &swp);
if (x+swp.cx>swpDesktop.cx)
x = swpDesktop.cx - swp.cx;
if (x<0)
x = 0;
if (y<0)
y = 0;
if (y+swp.cy>swpDesktop.cy)
y = swpDesktop.cy - swp.cy;
return WinSetWindowPos(hwnd, hwndInsertBehind, x, y, cx, cy, fl);
} else
if (fl & SWP_SIZE)
{
// Just sizing
WinQueryWindowPos(hwnd, &swp);
x = swp.x;
y = swp.y;
if (x+cx>swpDesktop.cx)
x = swpDesktop.cx - cx;
if (x<0)
x = 0;
if (y<0)
y = 0;
if (y+cy>swpDesktop.cy)
y = swpDesktop.cy - cy;
return WinSetWindowPos(hwnd, hwndInsertBehind, x, y, cx, cy, fl | SWP_MOVE);
} else
return WinSetWindowPos(hwnd, hwndInsertBehind, x, y, cx, cy, fl);
}
/////////////////////////////////////////////////////////////////////
//
// TranslateKey
//
// This creates SDL Keycodes from VK_ and hardware scan codes
//
/////////////////////////////////////////////////////////////////////
static SDL_keysym *TranslateKey(int vkey, int chcode, int scancode, SDL_keysym *keysym, int iPressed)
{
keysym->scancode = (unsigned char) scancode;
keysym->mod = KMOD_NONE;
keysym->unicode = 0;
if (iPressed && SDL_TranslateUNICODE)
{
// TODO:
// Implement real unicode conversion!
if (chcode)
keysym->unicode = chcode;
else
keysym->unicode = vkey;
}
keysym->sym = HWScanKeyMap[scancode];
// Now stuffs based on state of shift key(s)!
if (vkey == VK_SHIFT)
{
iShiftIsPressed = iPressed;
}
if ((iShiftIsPressed) && (SDL_TranslateUNICODE))
{
// Change syms, if Unicode stuff is required
// I think it's silly, but it's SDL...
switch (keysym->sym)
{
case SDLK_BACKQUOTE:
keysym->sym = '~';
break;
case SDLK_1:
keysym->sym = SDLK_EXCLAIM;
break;
case SDLK_2:
keysym->sym = SDLK_AT;
break;
case SDLK_3:
keysym->sym = SDLK_HASH;
break;
case SDLK_4:
keysym->sym = SDLK_DOLLAR;
break;
case SDLK_5:
keysym->sym = '%';
break;
case SDLK_6:
keysym->sym = SDLK_CARET;
break;
case SDLK_7:
keysym->sym = SDLK_AMPERSAND;
break;
case SDLK_8:
keysym->sym = SDLK_ASTERISK;
break;
case SDLK_9:
keysym->sym = SDLK_LEFTPAREN;
break;
case SDLK_0:
keysym->sym = SDLK_RIGHTPAREN;
break;
case SDLK_MINUS:
keysym->sym = SDLK_UNDERSCORE;
break;
case SDLK_PLUS:
keysym->sym = SDLK_EQUALS;
break;
case SDLK_LEFTBRACKET:
keysym->sym = '{';
break;
case SDLK_RIGHTBRACKET:
keysym->sym = '}';
break;
case SDLK_SEMICOLON:
keysym->sym = SDLK_COLON;
break;
case SDLK_QUOTE:
keysym->sym = SDLK_QUOTEDBL;
break;
case SDLK_BACKSLASH:
keysym->sym = '|';
break;
case SDLK_COMMA:
keysym->sym = SDLK_LESS;
break;
case SDLK_PERIOD:
keysym->sym = SDLK_GREATER;
break;
case SDLK_SLASH:
keysym->sym = SDLK_QUESTION;
break;
default:
break;
}
}
return keysym;
}
#define CONVERTMOUSEPOSITION() \
/* We have to inverse the mouse position, because every non-os/2 system */ \
/* has a coordinate system where the (0;0) is the top-left corner, */ \
/* while on os/2 it's the bottom left corner! */ \
if (FSLib_QueryFSMode(hwnd)) \
{ \
/* We're in FS mode! */ \
/* In FS mode our window is as big as fullscreen mode, but not necessary as */ \
/* big as the source buffer (can be bigger) */ \
/* So, limit mouse pos to source buffer size! */ \
if (ppts->x<0) ppts->x = 0; \
if (ppts->y<0) ppts->y = 0; \
if (ppts->x>=pVideo->hidden->SrcBufferDesc.uiXResolution) ppts->x = pVideo->hidden->SrcBufferDesc.uiXResolution-1; \
if (ppts->y>=pVideo->hidden->SrcBufferDesc.uiYResolution) ppts->y = pVideo->hidden->SrcBufferDesc.uiYResolution-1; \
pVideo->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account! */ \
ptl.x = ppts->x; ptl.y = ppts->y; \
WinMapWindowPoints(pVideo->hidden->hwndClient, HWND_DESKTOP, &ptl, 1); \
WinSetPointerPos(HWND_DESKTOP, ptl.x, ptl.y); \
/* Then convert OS/2 position to SDL position */ \
ppts->y = pVideo->hidden->SrcBufferDesc.uiYResolution - ppts->y - 1; \
} else \
{ \
SWP swpClient; \
/* We're in windowed mode! */ \
WinQueryWindowPos(pVideo->hidden->hwndClient, &swpClient); \
/* Convert OS/2 mouse position to SDL position, and also scale it! */ \
(ppts->x) = (ppts->x) * pVideo->hidden->SrcBufferDesc.uiXResolution / swpClient.cx; \
(ppts->y) = (ppts->y) * pVideo->hidden->SrcBufferDesc.uiYResolution / swpClient.cy; \
(ppts->y) = pVideo->hidden->SrcBufferDesc.uiYResolution - (ppts->y) - 1; \
}
/////////////////////////////////////////////////////////////////////
//
// WndProc
//
// This is the message processing window procedure for the
// SDLWindowClass, which is the client window in our application.
// It handles switching back and away from the app (taking care of
// going out and back to and from fullscreen mode), sending keystrokes
// and mouse events to where it has to be sent, etc...
//
/////////////////////////////////////////////////////////////////////
static MRESULT EXPENTRY WndProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
{
HPS ps;
RECTL rcl;
SDL_VideoDevice *pVideo = NULL;
switch (msg)
{
case WM_CHAR: // Keypress notification
#ifdef DEBUG_BUILD
// printf("WM_CHAR\n"); fflush(stdout);
#endif
pVideo = WinQueryWindowPtr(hwnd, 0);
if (pVideo)
{
/*
// We skip repeated keys:
if (CHARMSG(&msg)->cRepeat>1)
{
#ifdef DEBUG_BUILD
// printf("Repeated key (%d), skipping...\n", CHARMSG(&msg)->cRepeat); fflush(stdout);
#endif
return (MRESULT) TRUE;
}
*/
// If it's not repeated, then let's see if its pressed or released!
if (SHORT1FROMMP(mp1) & KC_KEYUP)
{
// A key has been released
SDL_keysym keysym;
#ifdef DEBUG_BUILD
// printf("WM_CHAR, keyup, code is [0x%0x]\n", CHAR4FROMMP(mp1)); // HW scan code
#endif
// One problem is with F1, which gets only the keyup message because
// it is a system key.
// So, when we get keyup message, we simulate keydown too!
// UPDATE:
// This problem should be solved now, that the accelerator keys are
// disabled for this window!
/*
if (SHORT2FROMMP(mp2)==VK_F1)
{
SDL_PrivateKeyboard(SDL_PRESSED, TranslateKey(SHORT2FROMMP(mp2), // VK_ code
SHORT1FROMMP(mp2), // Character code
CHAR4FROMMP(mp1), // HW Scan code
&keysym,0));
}*/
SDL_PrivateKeyboard(SDL_RELEASED, TranslateKey(SHORT2FROMMP(mp2), // VK_ code
SHORT1FROMMP(mp2), // Character code
CHAR4FROMMP(mp1), // HW Scan code
&keysym,0));
} else
{
// A key has been pressed
SDL_keysym keysym;
#ifdef DEBUG_BUILD
// printf("WM_CHAR, keydown, code is [0x%0x]\n", CHAR4FROMMP(mp1)); // HW scan code
#endif
// Check for fastkeys: ALT+HOME to toggle FS mode
// ALT+END to close app
if ((SHORT1FROMMP(mp1) & KC_ALT) &&
(SHORT2FROMMP(mp2) == VK_HOME))
{
#ifdef DEBUG_BUILD
printf(" Pressed ALT+HOME!\n"); fflush(stdout);
#endif
// Only switch between fullscreen and back if it's not
// a resizable mode!
if (
(!pVideo->hidden->pSDLSurface) ||
((pVideo->hidden->pSDLSurface)
&& ((pVideo->hidden->pSDLSurface->flags & SDL_RESIZABLE)==0)
)
)
FSLib_ToggleFSMode(hwnd, !FSLib_QueryFSMode(hwnd));
#ifdef DEBUG_BUILD
else
printf(" Resizable mode, so discarding ALT+HOME!\n"); fflush(stdout);
#endif
} else
if ((SHORT1FROMMP(mp1) & KC_ALT) &&
(SHORT2FROMMP(mp2) == VK_END))
{
#ifdef DEBUG_BUILD
printf(" Pressed ALT+END!\n"); fflush(stdout);
#endif
// Close window, and get out of loop!
// Also send event to SDL application, but we won't
// wait for it to be processed!
SDL_PrivateQuit();
WinPostMsg(hwnd, WM_QUIT, 0, 0);
} else
{
SDL_PrivateKeyboard(SDL_PRESSED, TranslateKey(SHORT2FROMMP(mp2), // VK_ code
SHORT1FROMMP(mp2), // Character code
CHAR4FROMMP(mp1), // HW Scan code
&keysym,1));
}
}
}
return (MRESULT) TRUE;
case WM_TRANSLATEACCEL:
{
PQMSG pqmsg;
pqmsg = (PQMSG) mp1;
if (mp1)
{
if (pqmsg->msg == WM_CHAR)
{
// WM_CHAR message!
// Let's filter the ALT keypress and all other acceleration keys!
return (MRESULT) FALSE;
}
}
break; // Default processing (pass to parent until frame control)
}
case WM_PAINT: // Window redraw!
#ifdef DEBUG_BUILD
printf("WM_PAINT (0x%x)\n", hwnd); fflush(stdout);
#endif
ps = WinBeginPaint(hwnd,0,&rcl);
pVideo = FSLib_GetUserParm(hwnd);
if (pVideo)
{
if (!pVideo->hidden->pSDLSurface)
{
RECTL rclRect;
// So, don't blit now!
#ifdef DEBUG_BUILD
printf("WM_PAINT : Skipping blit while resizing (Pre!)!\n"); fflush(stdout);
#endif
WinQueryWindowRect(hwnd, &rclRect);
// Fill with black
WinFillRect(ps, &rclRect, CLR_BLACK);
} else
{
if (DosRequestMutexSem(pVideo->hidden->hmtxUseSrcBuffer, 1000)==NO_ERROR)
{
int iTop, iLeft, iWidth, iHeight;
int iXScaleError, iYScaleError;
int iXScaleError2, iYScaleError2;
SWP swp;
// Re-blit the modified area!
// For this, we have to calculate the points, scaled!
WinQueryWindowPos(hwnd, &swp);
#ifdef DEBUG_BUILD
printf("WM_PAINT : WinSize: %d %d, BufSize: %d %d\n",
swp.cx,
swp.cy,
pVideo->hidden->SrcBufferDesc.uiXResolution,
pVideo->hidden->SrcBufferDesc.uiYResolution
);
fflush(stdout);
#endif
#ifndef RESIZE_EVEN_IF_RESIZABLE
// But only blit if the window is not resizable, or if
// the window is resizable and the source buffer size is the
// same as the destination buffer size!
if ((!pVideo->hidden->pSDLSurface) ||
((pVideo->hidden->pSDLSurface) &&
(pVideo->hidden->pSDLSurface->flags & SDL_RESIZABLE) &&
((swp.cx != pVideo->hidden->SrcBufferDesc.uiXResolution) ||
(swp.cy != pVideo->hidden->SrcBufferDesc.uiYResolution)
) &&
(!FSLib_QueryFSMode(hwnd))
)
)
{
RECTL rclRect;
// Resizable surface and in resizing!
// So, don't blit now!
#ifdef DEBUG_BUILD
printf("WM_PAINT : Skipping blit while resizing!\n"); fflush(stdout);
#endif
WinQueryWindowRect(hwnd, &rclRect);
// Fill with black
WinFillRect(ps, &rclRect, CLR_BLACK);
} else
#endif
{
iXScaleError = (pVideo->hidden->SrcBufferDesc.uiXResolution-1) / swp.cx;
iYScaleError = (pVideo->hidden->SrcBufferDesc.uiYResolution-1) / swp.cy;
if (iXScaleError<0) iXScaleError = 0;
if (iYScaleError<0) iYScaleError = 0;
iXScaleError2 = (swp.cx-1)/(pVideo->hidden->SrcBufferDesc.uiXResolution);
iYScaleError2 = (swp.cy-1)/(pVideo->hidden->SrcBufferDesc.uiYResolution);
if (iXScaleError2<0) iXScaleError2 = 0;
if (iYScaleError2<0) iYScaleError2 = 0;
iTop = (swp.cy - rcl.yTop) * pVideo->hidden->SrcBufferDesc.uiYResolution / swp.cy - iYScaleError;
iLeft = rcl.xLeft * pVideo->hidden->SrcBufferDesc.uiXResolution / swp.cx - iXScaleError;
iWidth = ((rcl.xRight-rcl.xLeft) * pVideo->hidden->SrcBufferDesc.uiXResolution + swp.cx-1)
/ swp.cx + 2*iXScaleError;
iHeight = ((rcl.yTop-rcl.yBottom) * pVideo->hidden->SrcBufferDesc.uiYResolution + swp.cy-1)
/ swp.cy + 2*iYScaleError;
iWidth+=iXScaleError2;
iHeight+=iYScaleError2;
if (iTop<0) iTop = 0;
if (iLeft<0) iLeft = 0;
if (iTop+iHeight>pVideo->hidden->SrcBufferDesc.uiYResolution) iHeight = pVideo->hidden->SrcBufferDesc.uiYResolution-iTop;
if (iLeft+iWidth>pVideo->hidden->SrcBufferDesc.uiXResolution) iWidth = pVideo->hidden->SrcBufferDesc.uiXResolution-iLeft;
#ifdef DEBUG_BUILD
printf("WM_PAINT : BitBlt: %d %d -> %d %d (Buf %d x %d)\n",
iTop, iLeft, iWidth, iHeight,
pVideo->hidden->SrcBufferDesc.uiXResolution,
pVideo->hidden->SrcBufferDesc.uiYResolution
);
fflush(stdout);
#endif
FSLIB_BITBLT(hwnd, pVideo->hidden->pchSrcBuffer, iTop, iLeft, iWidth, iHeight);
}
DosReleaseMutexSem(pVideo->hidden->hmtxUseSrcBuffer);
}
}
}
#ifdef DEBUG_BUILD
else
{
printf("WM_PAINT : No pVideo!\n"); fflush(stdout);
}
#endif
WinEndPaint(ps);
#ifdef DEBUG_BUILD
printf("WM_PAINT : Done.\n");
fflush(stdout);
#endif
return 0;
case WM_SIZE:
{
#ifdef DEBUG_BUILD
printf("WM_SIZE : (%d %d)\n",
SHORT1FROMMP(mp2), SHORT2FROMMP(mp2)); fflush(stdout);
#endif
iWindowSizeX = SHORT1FROMMP(mp2);
iWindowSizeY = SHORT2FROMMP(mp2);
bWindowResized = 1;
// Make sure the window will be redrawn
WinInvalidateRegion(hwnd, NULL, TRUE);
}
break;
case WM_FSLIBNOTIFICATION:
#ifdef DEBUG_BUILD
printf("WM_FSLIBNOTIFICATION\n"); fflush(stdout);
#endif
if ((int)mp1 == FSLN_TOGGLEFSMODE)
{
// FS mode changed, reblit image!
pVideo = FSLib_GetUserParm(hwnd);
if (pVideo)
{
if (!pVideo->hidden->pSDLSurface)
{
// Resizable surface and in resizing!
// So, don't blit now!
#ifdef DEBUG_BUILD
printf("WM_FSLIBNOTIFICATION : Can not blit if there is no surface, doing nothing.\n"); fflush(stdout);
#endif
} else
{
if (DosRequestMutexSem(pVideo->hidden->hmtxUseSrcBuffer, 1000)==NO_ERROR)
{
if (pVideo->hidden->pSDLSurface)
{
#ifndef RESIZE_EVEN_IF_RESIZABLE
SWP swp;
// But only blit if the window is not resizable, or if
// the window is resizable and the source buffer size is the
// same as the destination buffer size!
WinQueryWindowPos(hwnd, &swp);
if ((!pVideo->hidden->pSDLSurface) ||
(
(pVideo->hidden->pSDLSurface) &&
(pVideo->hidden->pSDLSurface->flags & SDL_RESIZABLE) &&
((swp.cx != pVideo->hidden->SrcBufferDesc.uiXResolution) ||
(swp.cy != pVideo->hidden->SrcBufferDesc.uiYResolution)
) &&
(!FSLib_QueryFSMode(hwnd))
)
)
{
// Resizable surface and in resizing!
// So, don't blit now!
#ifdef DEBUG_BUILD
printf("WM_FSLIBNOTIFICATION : Cannot blit while resizing, doing nothing.\n"); fflush(stdout);
#endif
} else
#endif
{
#ifdef DEBUG_BUILD
printf("WM_FSLIBNOTIFICATION : Blitting!\n"); fflush(stdout);
#endif
FSLIB_BITBLT(hwnd, pVideo->hidden->pchSrcBuffer,
0, 0,
pVideo->hidden->SrcBufferDesc.uiXResolution,
pVideo->hidden->SrcBufferDesc.uiYResolution);
}
}
#ifdef DEBUG_BUILD
else
printf("WM_FSLIBNOTIFICATION : No public surface!\n"); fflush(stdout);
#endif
DosReleaseMutexSem(pVideo->hidden->hmtxUseSrcBuffer);
}
}
}
}
return (MPARAM) 1;
case WM_ACTIVATE:
#ifdef DEBUG_BUILD
printf("WM_ACTIVATE\n"); fflush(stdout);
#endif
pVideo = FSLib_GetUserParm(hwnd);
if (pVideo)
{
pVideo->hidden->fInFocus = (int) mp1;
if (pVideo->hidden->fInFocus)
{
// Went into focus
if ((pVideo->hidden->iMouseVisible) && (!bMouseCaptured))
WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE));
else
WinSetPointer(HWND_DESKTOP, NULL);
if (bMouseCapturable)
{
// Re-capture the mouse, if we captured it before!
WinSetCapture(HWND_DESKTOP, hwnd);
bMouseCaptured = 1;
{
SWP swpClient;
POINTL ptl;
// Center the mouse to the middle of the window!
WinQueryWindowPos(pVideo->hidden->hwndClient, &swpClient);
ptl.x = 0; ptl.y = 0;
WinMapWindowPoints(pVideo->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
pVideo->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account! */
WinSetPointerPos(HWND_DESKTOP,
ptl.x + swpClient.cx/2,
ptl.y + swpClient.cy/2);
}
}
} else
{
// Went out of focus
WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE));
if (bMouseCaptured)
{
// Release the mouse
WinSetCapture(HWND_DESKTOP, hwnd);
bMouseCaptured = 0;
}
}
}
#ifdef DEBUG_BUILD
printf("WM_ACTIVATE done\n"); fflush(stdout);
#endif
break;
case WM_BUTTON1DOWN:
#ifdef DEBUG_BUILD
printf("WM_BUTTON1DOWN\n"); fflush(stdout);
#endif
pVideo = FSLib_GetUserParm(hwnd);
if (pVideo)
{
SDL_PrivateMouseButton(SDL_PRESSED,
SDL_BUTTON_LEFT,
0, 0); // Don't report mouse movement!
if (bMouseCapturable)
{
// We should capture the mouse!
if (!bMouseCaptured)
{
WinSetCapture(HWND_DESKTOP, hwnd);
WinSetPointer(HWND_DESKTOP, NULL);
bMouseCaptured = 1;
{
SWP swpClient;
POINTL ptl;
// Center the mouse to the middle of the window!
WinQueryWindowPos(pVideo->hidden->hwndClient, &swpClient);
ptl.x = 0; ptl.y = 0;
WinMapWindowPoints(pVideo->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
pVideo->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account! */
WinSetPointerPos(HWND_DESKTOP,
ptl.x + swpClient.cx/2,
ptl.y + swpClient.cy/2);
}
}
}
}
break;
case WM_BUTTON1UP:
#ifdef DEBUG_BUILD
printf("WM_BUTTON1UP\n"); fflush(stdout);
#endif
SDL_PrivateMouseButton(SDL_RELEASED,
SDL_BUTTON_LEFT,
0, 0); // Don't report mouse movement!
break;
case WM_BUTTON2DOWN:
#ifdef DEBUG_BUILD
printf("WM_BUTTON2DOWN\n"); fflush(stdout);
#endif
pVideo = FSLib_GetUserParm(hwnd);
if (pVideo)
{
SDL_PrivateMouseButton(SDL_PRESSED,
SDL_BUTTON_RIGHT,
0, 0); // Don't report mouse movement!
if (bMouseCapturable)
{
// We should capture the mouse!
if (!bMouseCaptured)
{
WinSetCapture(HWND_DESKTOP, hwnd);
WinSetPointer(HWND_DESKTOP, NULL);
bMouseCaptured = 1;
{
SWP swpClient;
POINTL ptl;
// Center the mouse to the middle of the window!
WinQueryWindowPos(pVideo->hidden->hwndClient, &swpClient);
ptl.x = 0; ptl.y = 0;
WinMapWindowPoints(pVideo->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
pVideo->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account! */
WinSetPointerPos(HWND_DESKTOP,
ptl.x + swpClient.cx/2,
ptl.y + swpClient.cy/2);
}
}
}
}
break;
case WM_BUTTON2UP:
#ifdef DEBUG_BUILD
printf("WM_BUTTON2UP\n"); fflush(stdout);
#endif
SDL_PrivateMouseButton(SDL_RELEASED,
SDL_BUTTON_RIGHT,
0, 0); // Don't report mouse movement!
break;
case WM_BUTTON3DOWN:
#ifdef DEBUG_BUILD
printf("WM_BUTTON3DOWN\n"); fflush(stdout);
#endif
pVideo = FSLib_GetUserParm(hwnd);
if (pVideo)
{
SDL_PrivateMouseButton(SDL_PRESSED,
SDL_BUTTON_MIDDLE,
0, 0); // Don't report mouse movement!
if (bMouseCapturable)
{
// We should capture the mouse!
if (!bMouseCaptured)
{
WinSetCapture(HWND_DESKTOP, hwnd);
WinSetPointer(HWND_DESKTOP, NULL);
bMouseCaptured = 1;
{
SWP swpClient;
POINTL ptl;
// Center the mouse to the middle of the window!
WinQueryWindowPos(pVideo->hidden->hwndClient, &swpClient);
ptl.x = 0; ptl.y = 0;
WinMapWindowPoints(pVideo->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
pVideo->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account! */
WinSetPointerPos(HWND_DESKTOP,
ptl.x + swpClient.cx/2,
ptl.y + swpClient.cy/2);
}
}
}
}
break;
case WM_BUTTON3UP:
#ifdef DEBUG_BUILD
printf("WM_BUTTON3UP\n"); fflush(stdout);
#endif
SDL_PrivateMouseButton(SDL_RELEASED,
SDL_BUTTON_MIDDLE,
0, 0); // Don't report mouse movement!
break;
case WM_MOUSEMOVE:
#ifdef DEBUG_BUILD
// printf("WM_MOUSEMOVE\n"); fflush(stdout);
#endif
pVideo = FSLib_GetUserParm(hwnd);
if (pVideo)
{
if (pVideo->hidden->iSkipWMMOUSEMOVE)
{
pVideo->hidden->iSkipWMMOUSEMOVE--;
} else
{
POINTS *ppts = (POINTS *) (&mp1);
POINTL ptl;
CONVERTMOUSEPOSITION();
if (bMouseCaptured)
{
SWP swpClient;
// Send relative mouse position, and re-center the mouse
// Reposition the mouse to the center of the screen/window
SDL_PrivateMouseMotion(0, // Buttons not changed
1, // Relative position
ppts->x - (pVideo->hidden->SrcBufferDesc.uiXResolution/2),
ppts->y+1 - (pVideo->hidden->SrcBufferDesc.uiYResolution/2));
WinQueryWindowPos(pVideo->hidden->hwndClient, &swpClient);
ptl.x = 0; ptl.y = 0;
WinMapWindowPoints(pVideo->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
pVideo->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account! */
// Center the mouse to the middle of the window!
WinSetPointerPos(HWND_DESKTOP,
ptl.x + swpClient.cx/2,
ptl.y + swpClient.cy/2);
} else
{
// Send absolute mouse position
SDL_PrivateMouseMotion(0, // Buttons not changed
0, // Absolute position
ppts->x,
ppts->y);
}
}
if ((pVideo->hidden->iMouseVisible) && (!bMouseCaptured))
{
#ifdef DEBUG_BUILD
// printf("WM_MOUSEMOVE : ptr = %p\n", hptrGlobalPointer); fflush(stdout);
#endif
if (hptrGlobalPointer)
WinSetPointer(HWND_DESKTOP, hptrGlobalPointer);
else
WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE));
}
else
{
WinSetPointer(HWND_DESKTOP, NULL);
}
}
#ifdef DEBUG_BUILD
// printf("WM_MOUSEMOVE done\n"); fflush(stdout);
#endif
return (MRESULT) FALSE;
case WM_CLOSE: // Window close
#ifdef DEBUG_BUILD
printf("WM_CLOSE\n"); fflush(stdout);
#endif
pVideo = FSLib_GetUserParm(hwnd);
if (pVideo)
{
// Send Quit message to the SDL application!
SDL_PrivateQuit();
return 0;
}
break;
#ifdef BITBLT_IN_WINMESSAGEPROC
case WM_UPDATERECTSREQUEST:
pVideo = FSLib_GetUserParm(hwnd);
if ((pVideo) && (pVideo->hidden->pSDLSurface))
{
if (DosRequestMutexSem(pVideo->hidden->hmtxUseSrcBuffer, SEM_INDEFINITE_WAIT)==NO_ERROR)
{
int numrects;
SDL_Rect *rects;
int i;
SWP swp;
numrects = (int) mp1;
rects = (SDL_Rect *) mp2;
WinQueryWindowPos(hwnd, &swp);
#ifndef RESIZE_EVEN_IF_RESIZABLE
if ((!pVideo->hidden->pSDLSurface) ||
(
(pVideo->hidden->pSDLSurface) &&
(pVideo->hidden->pSDLSurface->flags & SDL_RESIZABLE) &&
((swp.cx != pVideo->hidden->SrcBufferDesc.uiXResolution) ||
(swp.cy != pVideo->hidden->SrcBufferDesc.uiYResolution)
) &&
(!FSLib_QueryFSMode(hwnd))
)
)
{
// Resizable surface and in resizing!
// So, don't blit now!
#ifdef DEBUG_BUILD
printf("[WM_UPDATERECTSREQUEST] : Skipping blit while resizing!\n"); fflush(stdout);
#endif
} else
#endif
{
#ifdef DEBUG_BUILD
printf("[WM_UPDATERECTSREQUEST] : Blitting!\n"); fflush(stdout);
#endif
// Blit the changed areas
for (i=0; i<numrects; i++)
FSLIB_BITBLT(hwnd, pVideo->hidden->pchSrcBuffer,
rects[i].y, rects[i].x, rects[i].w, rects[i].h);
}
DosReleaseMutexSem(pVideo->hidden->hmtxUseSrcBuffer);
}
}
return 0;
#endif
default:
#ifdef DEBUG_BUILD
printf("Unhandled: %x\n", msg); fflush(stdout);
#endif
break;
}
// Run the default window procedure for unhandled stuffs
return WinDefWindowProc(hwnd, msg, mp1, mp2);
}
/////////////////////////////////////////////////////////////////////
//
// PMThreadFunc
//
// This function implements the PM-Thread, which initializes the
// application window itself, the DIVE, and start message processing.
//
/////////////////////////////////////////////////////////////////////
int iNumOfPMThreadInstances = 0; // Global!
static void PMThreadFunc(void *pParm)
{
SDL_VideoDevice *pVideo = pParm;
HAB hab;
HMQ hmq;
QMSG msg;
ULONG fcf;
#ifdef DEBUG_BUILD
printf("[PMThreadFunc] : Starting\n"); fflush(stdout);
#endif
iNumOfPMThreadInstances++;
// Initialize PM, create a message queue.
hab=WinInitialize(0);
hmq=WinCreateMsgQueue(hab,0);
if (hmq==0)
{
#ifdef DEBUG_BUILD
printf("[PMThreadFunc] : Could not create message queue!\n");
printf(" It might be that the application using SDL is not a PM app!\n");
fflush(stdout);
#endif
pVideo->hidden->iPMThreadStatus = 2;
} else
{
int rc;
RECTL rectl;
fcf = ulFCFToUse; // Get from global setting
#ifdef DEBUG_BUILD
printf("[PMThreadFunc] : FSLib_CreateWindow()!\n");
fflush(stdout);
#endif
rc = FSLib_CreateWindow(HWND_DESKTOP, 0, &fcf,
"SDL Application",
NULLHANDLE, 0,
&(pVideo->hidden->SrcBufferDesc),
WndProc,
&(pVideo->hidden->hwndClient),
&(pVideo->hidden->hwndFrame));
#ifdef DEBUG_BUILD
printf("[PMThreadFunc] : FSLib_CreateWindow() rc = %d\n", rc);
fflush(stdout);
#endif
if (!rc)
{
#ifdef DEBUG_BUILD
printf("[PMThreadFunc] : Could not create FSLib window!\n");
fflush(stdout);
#endif
pVideo->hidden->iPMThreadStatus = 3;
} else
{
#ifdef DEBUG_BUILD
printf("[PMThreadFunc] : FSLib_AddUserParm()!\n");
fflush(stdout);
#endif
// Store pVideo pointer in window data for client window, so
// it will know the instance to which it belongs to.
FSLib_AddUserParm(pVideo->hidden->hwndClient, pVideo);
// Now set default image width height and fourcc!
#ifdef DEBUG_BUILD
printf("[PMThreadFunc] : SetWindowPos()!\n");
fflush(stdout);
#endif
// Set the position and size of the main window,
// and make it visible!
// Calculate frame window size from client window size
rectl.xLeft = 0;
rectl.yBottom = 0;
rectl.xRight = pVideo->hidden->SrcBufferDesc.uiXResolution; // Noninclusive
rectl.yTop = pVideo->hidden->SrcBufferDesc.uiYResolution; // Noninclusive
WinCalcFrameRect(pVideo->hidden->hwndFrame, &rectl, FALSE);
SetAccessableWindowPos(pVideo->hidden->hwndFrame,
HWND_TOP,
(WinQuerySysValue (HWND_DESKTOP, SV_CXSCREEN) - (rectl.xRight-rectl.xLeft)) / 2,
(WinQuerySysValue (HWND_DESKTOP, SV_CYSCREEN) - (rectl.yTop-rectl.yBottom)) / 2,
(rectl.xRight-rectl.xLeft),
(rectl.yTop-rectl.yBottom),
SWP_SIZE | SWP_ACTIVATE | SWP_SHOW | SWP_MOVE);
#ifdef DEBUG_BUILD
printf("[PMThreadFunc] : Entering message loop\n"); fflush(stdout);
#endif
pVideo->hidden->iPMThreadStatus = 1;
while (WinGetMsg(hab, (PQMSG)&msg, 0, 0, 0))
WinDispatchMsg(hab, (PQMSG) &msg);
#ifdef DEBUG_BUILD
printf("[PMThreadFunc] : Leaving message loop\n"); fflush(stdout);
#endif
// We should release the captured the mouse!
if (bMouseCaptured)
{
WinSetCapture(HWND_DESKTOP, NULLHANDLE);
bMouseCaptured = 0;
}
// Destroy our window
WinDestroyWindow(pVideo->hidden->hwndFrame); pVideo->hidden->hwndFrame=NULL;
// Show pointer to make sure it will not be left hidden.
WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE));
WinShowPointer(HWND_DESKTOP, TRUE);
}
// Uninitialize PM
WinDestroyMsgQueue(hmq);
// All done!
pVideo->hidden->iPMThreadStatus = 0;
}
WinTerminate(hab);
/* Commented out, should not be needed anymore, because we send it
from WM_CLOSE.
// Notify SDL that it should really die now...
SDL_PrivateQuit(); SDL_PrivateQuit(); SDL_PrivateQuit(); //... :))
*/
#ifdef DEBUG_BUILD
printf("[PMThreadFunc] : End, status is %d!\n", pVideo->hidden->iPMThreadStatus); fflush(stdout);
#endif
iNumOfPMThreadInstances--;
// HACK to prevent zombie and hanging SDL applications, which does not take
// care of closing the window for some reason:
// There are some apps which do not process messages, so do a lot of things
// without noticing that the application should close. To close these,
// I've thought about the following:
// If the window is closed (the execution came here), I wait a bit to
// give time to the app to finish its execution. If it does not, I kill it
// using DosExit(). Brute force, but should work.
if (pVideo->hidden->iPMThreadStatus==0)
{
DosSleep(5000); // Wait 5 secs
// If a new PM thread has been spawned (reinitializing video mode), then all right.
// Otherwise, we have a problem, the app doesn't want to stop. Kill!
if (iNumOfPMThreadInstances==0)
{
#ifdef DEBUG_BUILD
printf("[PMThreadFunc] : It seems that the application haven't terminated itself\n"); fflush(stdout);
printf("[PMThreadFunc] : in the last 5 seconds, so we go berserk.\n"); fflush(stdout);
printf("[PMThreadFunc] : Brute force mode. :) Killing process! Dieeeee...\n"); fflush(stdout);
#endif
DosExit(EXIT_PROCESS, -1);
}
}
_endthread();
}
struct WMcursor
{
HBITMAP hbm;
HPOINTER hptr;
char *pchData;
};
/* Free a window manager cursor */
void os2fslib_FreeWMCursor(_THIS, WMcursor *cursor)
{
if (cursor)
{
GpiDeleteBitmap(cursor->hbm);
WinDestroyPointer(cursor->hptr);
free(cursor->pchData);
free(cursor);
}
}
/* Local functions to convert the SDL cursor mask into OS/2 format */
static void memnot(Uint8 *dst, Uint8 *src, int len)
{
while ( len-- > 0 )
*dst++ = ~*src++;
}
static void memxor(Uint8 *dst, Uint8 *src1, Uint8 *src2, int len)
{
while ( len-- > 0 )
*dst++ = (*src1++)^(*src2++);
}
/* Create a black/white window manager cursor */
WMcursor *os2fslib_CreateWMCursor_Win(_THIS, Uint8 *data, Uint8 *mask,
int w, int h, int hot_x, int hot_y)
{
HPOINTER hptr;
HBITMAP hbm;
BITMAPINFOHEADER bmih;
BMPINFO bmi;
HPS hps;
char *pchTemp;
char *xptr, *aptr;
int maxx, maxy;
int i, run, pad;
WMcursor *pResult;
maxx = WinQuerySysValue(HWND_DESKTOP, SV_CXPOINTER);
maxy = WinQuerySysValue(HWND_DESKTOP, SV_CYPOINTER);
// Check for max size!
if ((w>maxx) || (h>maxy))
return (WMcursor *) NULL;
pResult = (WMcursor *) malloc(sizeof(WMcursor));
if (!pResult) return (WMcursor *) NULL;
pchTemp = (char *) malloc((maxx + 7)/8 * maxy*2);
if (!pchTemp)
{
free(pResult);
return (WMcursor *) NULL;
}
memset(pchTemp, 0, (maxx + 7)/8 * maxy*2);
hps = WinGetPS(_this->hidden->hwndClient);
bmi.cbFix = sizeof(BITMAPINFOHEADER);
bmi.cx = maxx;
bmi.cy = 2*maxy;
bmi.cPlanes = 1;
bmi.cBitCount = 1;
bmi.argbColor[0].bBlue = 0x00;
bmi.argbColor[0].bGreen = 0x00;
bmi.argbColor[0].bRed = 0x00;
bmi.argbColor[1].bBlue = 0x00;
bmi.argbColor[1].bGreen = 0x00;
bmi.argbColor[1].bRed = 0xff;
memset(&bmih, 0, sizeof(BITMAPINFOHEADER));
bmih.cbFix = sizeof(BITMAPINFOHEADER);
bmih.cx = maxx;
bmih.cy = 2*maxy;
bmih.cPlanes = 1;
bmih.cBitCount = 1;
run = (w+7)/8;
pad = (maxx+7)/8 - run;
for (i=0; i<h; i++)
{
xptr = pchTemp + (maxx+7)/8 * (maxy-1-i);
aptr = pchTemp + (maxx+7)/8 * (maxy+maxy-1-i);
memxor(xptr, data, mask, run);
xptr += run;
data += run;
memnot(aptr, mask, run);
mask += run;
aptr += run;
memset(xptr, 0, pad);
xptr += pad;
memset(aptr, ~0, pad);
aptr += pad;
}
pad += run;
for (i=h ; i<maxy; i++ )
{
xptr = pchTemp + (maxx+7)/8 * (maxy-1-i);
aptr = pchTemp + (maxx+7)/8 * (maxy+maxy-1-i);
memset(xptr, 0, (maxx+7)/8);
xptr += (maxx+7)/8;
memset(aptr, ~0, (maxx+7)/8);
aptr += (maxx+7)/8;
}
hbm = GpiCreateBitmap(hps, (PBITMAPINFOHEADER2)&bmih, CBM_INIT, (PBYTE) pchTemp, (PBITMAPINFO2)&bmi);
hptr = WinCreatePointer(HWND_DESKTOP, hbm, TRUE, hot_x, maxy - hot_y - 1);
#ifdef DEBUG_BUILD
printf("HotSpot : %d ; %d\n", hot_x, hot_y);
printf("HPS returned : %x\n", (ULONG)hps);
printf("HBITMAP returned : %x\n", (ULONG)hbm);
printf("HPOINTER returned: %x\n", (ULONG)hptr);
#endif
WinReleasePS(hps);
#ifdef DEBUG_BUILD
printf("[CreateWMCursor] : ptr = %p\n", hptr); fflush(stdout);
#endif
pResult->hptr = hptr;
pResult->hbm = hbm;
pResult->pchData = pchTemp;
#ifdef DEBUG_BUILD
printf("[CreateWMCursor] : ptr = %p return.\n", hptr); fflush(stdout);
#endif
return (WMcursor *) pResult;
}
WMcursor *os2fslib_CreateWMCursor_FS(_THIS, Uint8 *data, Uint8 *mask,
int w, int h, int hot_x, int hot_y)
{
#ifdef DEBUG_BUILD
printf("[CreateWMCursor_FS] : returning pointer NULL\n"); fflush(stdout);
#endif
// In FS mode we'll use software cursor
return (WMcursor *) NULL;
}
/* Show the specified cursor, or hide if cursor is NULL */
int os2fslib_ShowWMCursor(_THIS, WMcursor *cursor)
{
#ifdef DEBUG_BUILD
printf("[ShowWMCursor] : ptr = %p\n", cursor); fflush(stdout);
#endif
if (cursor)
{
WinSetPointer(HWND_DESKTOP, cursor->hptr);
hptrGlobalPointer = cursor->hptr;
_this->hidden->iMouseVisible = 1;
}
else
{
WinSetPointer(HWND_DESKTOP, FALSE);
hptrGlobalPointer = NULL;
_this->hidden->iMouseVisible = 0;
}
#ifdef DEBUG_BUILD
printf("[ShowWMCursor] : ptr = %p, DONE\n", cursor); fflush(stdout);
#endif
return 1;
}
/* Warp the window manager cursor to (x,y)
If NULL, a mouse motion event is posted internally.
*/
void os2fslib_WarpWMCursor(_THIS, Uint16 x, Uint16 y)
{
LONG lx, ly;
SWP swpClient;
POINTL ptlPoints;
WinQueryWindowPos(_this->hidden->hwndClient, &swpClient);
ptlPoints.x = swpClient.x;
ptlPoints.y = swpClient.y;
WinMapWindowPoints(_this->hidden->hwndFrame, HWND_DESKTOP, &ptlPoints, 1);
lx = ptlPoints.x + (x*swpClient.cx) / _this->hidden->SrcBufferDesc.uiXResolution;
ly = ptlPoints.y + swpClient.cy - ((y*swpClient.cy) / _this->hidden->SrcBufferDesc.uiYResolution) - 1;
SDL_PrivateMouseMotion(0, // Buttons not changed
0, // Absolute position
x,
y);
WinSetPointerPos(HWND_DESKTOP, lx, ly);
}
/* If not NULL, this is called when a mouse motion event occurs */
void os2fslib_MoveWMCursor(_THIS, int x, int y)
{
/*
SDL_Rect rect;
#ifdef DEBUG_BUILD
printf("[MoveWMCursor] : at %d ; %d\n", x, y); fflush(stdout);
#endif
rect.x = x;
rect.y = y;
rect.w = 32;
rect.h = 32;
os2fslib_UpdateRects(_this, 1, &rect);
// TODO!
*/
}
/* Determine whether the mouse should be in relative mode or not.
This function is called when the input grab state or cursor
visibility state changes.
If the cursor is not visible, and the input is grabbed, the
driver can place the mouse in relative mode, which may result
in higher accuracy sampling of the pointer motion.
*/
void os2fslib_CheckMouseMode(_THIS)
{
}
static void os2fslib_PumpEvents(_THIS)
{
// Notify SDL that if window has been resized!
if (
(_this->hidden->pSDLSurface) &&
(_this->hidden->pSDLSurface->flags & SDL_RESIZABLE) &&
(
(_this->hidden->SrcBufferDesc.uiXResolution!=iWindowSizeX) ||
(_this->hidden->SrcBufferDesc.uiYResolution!=iWindowSizeY)
) &&
(iWindowSizeX>0) &&
(iWindowSizeY>0)
)
{
static time_t prev_time;
time_t curr_time;
curr_time = time(NULL);
if ((difftime(curr_time, prev_time)>=0.25) ||
(bWindowResized))
{
// Make sure we won't flood the event queue with resize events,
// only send them at 250 msecs!
// (or when the window is resized)
#ifdef DEBUG_BUILD
printf("[os2fslib_PumpEvents] : Calling PrivateResize (%d %d).\n",
iWindowSizeX, iWindowSizeY);
fflush(stdout);
#endif
// Tell SDL the new size
SDL_PrivateResize(iWindowSizeX, iWindowSizeY);
prev_time = curr_time;
bWindowResized = 0;
}
}
}
/* We don't actually allow hardware surfaces other than the main one */
static int os2fslib_AllocHWSurface(_THIS, SDL_Surface *surface)
{
return(-1);
}
static void os2fslib_FreeHWSurface(_THIS, SDL_Surface *surface)
{
return;
}
/* We need to wait for vertical retrace on page flipped displays */
static int os2fslib_LockHWSurface(_THIS, SDL_Surface *surface)
{
return(0);
}
static void os2fslib_UnlockHWSurface(_THIS, SDL_Surface *surface)
{
return;
}
static int os2fslib_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
{
printf("[os2fslib_SetColors] : TODO!\n"); fflush(stdout);
// TODO: Implement paletted modes
return(1);
}
static void os2fslib_DestroyIcon(HWND hwndFrame)
{
if (hptrCurrentIcon)
{
WinDestroyPointer(hptrCurrentIcon);
hptrCurrentIcon = NULL;
WinSendMsg(hwndFrame,
WM_SETICON,
NULL,
NULL);
}
}
/* Set the window icon image */
void os2fslib_SetIcon(_THIS, SDL_Surface *icon, Uint8 *mask)
{
HWND hwndFrame;
SDL_Surface *icon_rgb;
HPOINTER hptrIcon;
HBITMAP hbm;
BITMAPINFOHEADER bmih;
BMPINFO bmi;
HPS hps;
char *pchTemp;
char *pptr, *mptr, *dptr, *dmptr;
int maxx, maxy, w, h, x, y;
SDL_Rect bounds;
#ifdef DEBUG_BUILD
printf("[os2fslib_SetIcon] : Creating and setting new icon\n"); fflush(stdout);
#endif
hwndFrame = WinQueryWindow(_this->hidden->hwndClient, QW_PARENT);
// Make sure the old icon resource will be free'd!
os2fslib_DestroyIcon(hwndFrame);
if ((!icon) || (!mask))
return;
w = icon->w;
h = icon->h;
maxx = WinQuerySysValue(HWND_DESKTOP, SV_CXICON);
maxy = WinQuerySysValue(HWND_DESKTOP, SV_CYICON);
// Check for max size!
if ((w>maxx) || (h>maxy))
return;
pchTemp = (char *) malloc(w * h*2 * 4);
if (!pchTemp)
return;
memset(pchTemp, 0, w * h*2 * 4);
// Convert surface to RGB, if it's not RGB yet!
icon_rgb = SDL_CreateRGBSurface(SDL_SWSURFACE, icon->w, icon->h,
32, 0, 0, 0, 0);
if ( icon_rgb == NULL )
{
free(pchTemp);
return;
}
bounds.x = 0;
bounds.y = 0;
bounds.w = icon->w;
bounds.h = icon->h;
if ( SDL_LowerBlit(icon, &bounds, icon_rgb, &bounds) < 0 )
{
SDL_FreeSurface(icon_rgb);
free(pchTemp);
return;
}
/* Copy pixels upside-down from RGB surface into BMP, masked with the icon mask */
// Pixels
pptr = (char *) (icon_rgb->pixels);
// Mask
mptr = mask;
for (y=0; y<h; y++)
{
unsigned char uchMaskByte;
// Destination
dptr = pchTemp + w*4 * (h-y-1);
// Destination mask
dmptr = pchTemp + w*h*4 + w*4 * (h-y-1);
for (x=0; x<w; x++)
{
if (x%8==0)
{
uchMaskByte = (unsigned char) (*mptr);
mptr++;
} else
uchMaskByte <<= 1;
if (uchMaskByte & 0x80)
{
// Copy RGB
*dptr++ = *pptr++;
*dptr++ = *pptr++;
*dptr++ = *pptr++;
*dptr++ = *pptr++;
*dmptr++ = 0;
*dmptr++ = 0;
*dmptr++ = 0;
*dmptr++ = 0;
} else
{
// Set pixels to fully transparent
*dptr++ = 0; pptr++;
*dptr++ = 0; pptr++;
*dptr++ = 0; pptr++;
*dptr++ = 0; pptr++;
*dmptr++ = 255;
*dmptr++ = 255;
*dmptr++ = 255;
*dmptr++ = 255;
}
}
}
// There is no more need for the RGB surface
SDL_FreeSurface(icon_rgb);
hps = WinGetPS(_this->hidden->hwndClient);
bmi.cbFix = sizeof(BITMAPINFOHEADER);
bmi.cx = w;
bmi.cy = 2*h;
bmi.cPlanes = 1;
bmi.cBitCount = 32;
memset(&bmih, 0, sizeof(BITMAPINFOHEADER));
bmih.cbFix = sizeof(BITMAPINFOHEADER);
bmih.cx = w;
bmih.cy = 2*h;
bmih.cPlanes = 1;
bmih.cBitCount = 32;
hbm = GpiCreateBitmap(hps, (PBITMAPINFOHEADER2)&bmih, CBM_INIT, (PBYTE) pchTemp, (PBITMAPINFO2)&bmi);
hptrIcon = WinCreatePointer(HWND_DESKTOP, hbm, FALSE, 0, 0);
WinReleasePS(hps);
// Free pixel array
free(pchTemp);
// Change icon in frame window
WinSendMsg(hwndFrame,
WM_SETICON,
(MPARAM) hptrIcon,
NULL);
/*
// Change icon in switchlist
// Seems like it's not needed, the WM_SETICON already does it.
{
PID pidFrame;
HSWITCH hswitchFrame;
SWCNTRL swctl;
WinQueryWindowProcess(hwndFrame, &pidFrame, NULL);
hswitchFrame = WinQuerySwitchHandle(hwndFrame, pidFrame);
WinQuerySwitchEntry(hswitchFrame, &swctl);
swctl.hwndIcon = hptrIcon;
WinChangeSwitchEntry(hswitchFrame, &swctl);
}
*/
// Store icon handle in global variable
hptrCurrentIcon = hptrIcon;
}
// ------------------------ REAL FUNCTIONS -----------------
static void os2fslib_SetCursorManagementFunctions(_THIS, int iForWindowedMode)
{
if (iForWindowedMode)
{
_this->FreeWMCursor = os2fslib_FreeWMCursor;
_this->CreateWMCursor = os2fslib_CreateWMCursor_Win;
_this->ShowWMCursor = os2fslib_ShowWMCursor;
_this->WarpWMCursor = os2fslib_WarpWMCursor;
_this->MoveWMCursor = os2fslib_MoveWMCursor;
_this->CheckMouseMode = NULL;//os2fslib_CheckMouseMode;
} else
{
// We'll have software mouse cursor in FS mode!
_this->FreeWMCursor = os2fslib_FreeWMCursor;
_this->CreateWMCursor = os2fslib_CreateWMCursor_FS;
_this->ShowWMCursor = os2fslib_ShowWMCursor;
_this->WarpWMCursor = os2fslib_WarpWMCursor;
_this->MoveWMCursor = os2fslib_MoveWMCursor;
_this->CheckMouseMode = NULL;//os2fslib_CheckMouseMode;
}
}
static void os2fslib_InitOSKeymap(_THIS)
{
int i;
iShiftIsPressed = 0;
/* Map the VK and CH keysyms */
for ( i=0; i<=255; ++i )
HWScanKeyMap[i] = SDLK_UNKNOWN;
// First line of keyboard:
HWScanKeyMap[0x1] = SDLK_ESCAPE;
HWScanKeyMap[0x3b] = SDLK_F1;
HWScanKeyMap[0x3c] = SDLK_F2;
HWScanKeyMap[0x3d] = SDLK_F3;
HWScanKeyMap[0x3e] = SDLK_F4;
HWScanKeyMap[0x3f] = SDLK_F5;
HWScanKeyMap[0x40] = SDLK_F6;
HWScanKeyMap[0x41] = SDLK_F7;
HWScanKeyMap[0x42] = SDLK_F8;
HWScanKeyMap[0x43] = SDLK_F9;
HWScanKeyMap[0x44] = SDLK_F10;
HWScanKeyMap[0x57] = SDLK_F11;
HWScanKeyMap[0x58] = SDLK_F12;
HWScanKeyMap[0x5d] = SDLK_PRINT;
HWScanKeyMap[0x46] = SDLK_SCROLLOCK;
HWScanKeyMap[0x5f] = SDLK_PAUSE;
// Second line of keyboard:
HWScanKeyMap[0x29] = SDLK_BACKQUOTE;
HWScanKeyMap[0x2] = SDLK_1;
HWScanKeyMap[0x3] = SDLK_2;
HWScanKeyMap[0x4] = SDLK_3;
HWScanKeyMap[0x5] = SDLK_4;
HWScanKeyMap[0x6] = SDLK_5;
HWScanKeyMap[0x7] = SDLK_6;
HWScanKeyMap[0x8] = SDLK_7;
HWScanKeyMap[0x9] = SDLK_8;
HWScanKeyMap[0xa] = SDLK_9;
HWScanKeyMap[0xb] = SDLK_0;
HWScanKeyMap[0xc] = SDLK_MINUS;
HWScanKeyMap[0xd] = SDLK_EQUALS;
HWScanKeyMap[0xe] = SDLK_BACKSPACE;
HWScanKeyMap[0x68] = SDLK_INSERT;
HWScanKeyMap[0x60] = SDLK_HOME;
HWScanKeyMap[0x62] = SDLK_PAGEUP;
HWScanKeyMap[0x45] = SDLK_NUMLOCK;
HWScanKeyMap[0x5c] = SDLK_KP_DIVIDE;
HWScanKeyMap[0x37] = SDLK_KP_MULTIPLY;
HWScanKeyMap[0x4a] = SDLK_KP_MINUS;
// Third line of keyboard:
HWScanKeyMap[0xf] = SDLK_TAB;
HWScanKeyMap[0x10] = SDLK_q;
HWScanKeyMap[0x11] = SDLK_w;
HWScanKeyMap[0x12] = SDLK_e;
HWScanKeyMap[0x13] = SDLK_r;
HWScanKeyMap[0x14] = SDLK_t;
HWScanKeyMap[0x15] = SDLK_y;
HWScanKeyMap[0x16] = SDLK_u;
HWScanKeyMap[0x17] = SDLK_i;
HWScanKeyMap[0x18] = SDLK_o;
HWScanKeyMap[0x19] = SDLK_p;
HWScanKeyMap[0x1a] = SDLK_LEFTBRACKET;
HWScanKeyMap[0x1b] = SDLK_RIGHTBRACKET;
HWScanKeyMap[0x1c] = SDLK_RETURN;
HWScanKeyMap[0x69] = SDLK_DELETE;
HWScanKeyMap[0x65] = SDLK_END;
HWScanKeyMap[0x67] = SDLK_PAGEDOWN;
HWScanKeyMap[0x47] = SDLK_KP7;
HWScanKeyMap[0x48] = SDLK_KP8;
HWScanKeyMap[0x49] = SDLK_KP9;
HWScanKeyMap[0x4e] = SDLK_KP_PLUS;
// Fourth line of keyboard:
HWScanKeyMap[0x3a] = SDLK_CAPSLOCK;
HWScanKeyMap[0x1e] = SDLK_a;
HWScanKeyMap[0x1f] = SDLK_s;
HWScanKeyMap[0x20] = SDLK_d;
HWScanKeyMap[0x21] = SDLK_f;
HWScanKeyMap[0x22] = SDLK_g;
HWScanKeyMap[0x23] = SDLK_h;
HWScanKeyMap[0x24] = SDLK_j;
HWScanKeyMap[0x25] = SDLK_k;
HWScanKeyMap[0x26] = SDLK_l;
HWScanKeyMap[0x27] = SDLK_SEMICOLON;
HWScanKeyMap[0x28] = SDLK_QUOTE;
HWScanKeyMap[0x2b] = SDLK_BACKSLASH;
HWScanKeyMap[0x4b] = SDLK_KP4;
HWScanKeyMap[0x4c] = SDLK_KP5;
HWScanKeyMap[0x4d] = SDLK_KP6;
// Fifth line of keyboard:
HWScanKeyMap[0x2a] = SDLK_LSHIFT;
HWScanKeyMap[0x56] = SDLK_WORLD_1; // Code 161, letter i' on hungarian keyboard
HWScanKeyMap[0x2c] = SDLK_z;
HWScanKeyMap[0x2d] = SDLK_x;
HWScanKeyMap[0x2e] = SDLK_c;
HWScanKeyMap[0x2f] = SDLK_v;
HWScanKeyMap[0x30] = SDLK_b;
HWScanKeyMap[0x31] = SDLK_n;
HWScanKeyMap[0x32] = SDLK_m;
HWScanKeyMap[0x33] = SDLK_COMMA;
HWScanKeyMap[0x34] = SDLK_PERIOD;
HWScanKeyMap[0x35] = SDLK_SLASH;
HWScanKeyMap[0x36] = SDLK_RSHIFT;
HWScanKeyMap[0x61] = SDLK_UP;
HWScanKeyMap[0x4f] = SDLK_KP1;
HWScanKeyMap[0x50] = SDLK_KP2;
HWScanKeyMap[0x51] = SDLK_KP3;
HWScanKeyMap[0x5a] = SDLK_KP_ENTER;
// Sixth line of keyboard:
HWScanKeyMap[0x1d] = SDLK_LCTRL;
HWScanKeyMap[0x7e] = SDLK_LSUPER; // Windows key
HWScanKeyMap[0x38] = SDLK_LALT;
HWScanKeyMap[0x39] = SDLK_SPACE;
HWScanKeyMap[0x5e] = SDLK_RALT;// Actually, altgr on my keyboard...
HWScanKeyMap[0x7f] = SDLK_RSUPER;
HWScanKeyMap[0x7c] = SDLK_MENU;
HWScanKeyMap[0x5b] = SDLK_RCTRL;
HWScanKeyMap[0x63] = SDLK_LEFT;
HWScanKeyMap[0x66] = SDLK_DOWN;
HWScanKeyMap[0x64] = SDLK_RIGHT;
HWScanKeyMap[0x52] = SDLK_KP0;
HWScanKeyMap[0x53] = SDLK_KP_PERIOD;
}
/* Iconify the window.
This function returns 1 if there is a window manager and the
window was actually iconified, it returns 0 otherwise.
*/
int os2fslib_IconifyWindow(_THIS)
{
HAB hab;
HMQ hmq;
ERRORID hmqerror;
// If there is no more window, nothing we can do!
if (_this->hidden->iPMThreadStatus!=1) return 0;
// Cannot do anything in fullscreen mode!
if (FSLib_QueryFSMode(_this->hidden->hwndClient))
return 0;
// Make sure this thread is prepared for using the Presentation Manager!
hab = WinInitialize(0);
hmq = WinCreateMsgQueue(hab,0);
// Remember if there was an error at WinCreateMsgQueue(), because we don't
// want to destroy somebody else's queue later. :)
hmqerror = WinGetLastError(hab);
WinSetWindowPos(_this->hidden->hwndFrame, HWND_TOP,
0, 0, 0, 0, SWP_MINIMIZE);
// Now destroy the message queue, if we've created it!
if (ERRORIDERROR(hmqerror)==0)
WinDestroyMsgQueue(hmq);
return 1;
}
static SDL_GrabMode os2fslib_GrabInput(_THIS, SDL_GrabMode mode)
{
HAB hab;
HMQ hmq;
ERRORID hmqerror;
// If there is no more window, nothing we can do!
if (_this->hidden->iPMThreadStatus!=1)
return SDL_GRAB_OFF;
// Make sure this thread is prepared for using the Presentation Manager!
hab = WinInitialize(0);
hmq = WinCreateMsgQueue(hab,0);
// Remember if there was an error at WinCreateMsgQueue(), because we don't
// want to destroy somebody else's queue later. :)
hmqerror = WinGetLastError(hab);
if (mode == SDL_GRAB_OFF)
{
#ifdef DEBUG_BUILD
printf("[os2fslib_GrabInput] : Releasing mouse\n"); fflush(stdout);
#endif
// Release the mouse
bMouseCapturable = 0;
if (bMouseCaptured)
{
WinSetCapture(HWND_DESKTOP, NULLHANDLE);
bMouseCaptured = 0;
}
} else
{
#ifdef DEBUG_BUILD
printf("[os2fslib_GrabInput] : Capturing mouse\n"); fflush(stdout);
#endif
// Capture the mouse
bMouseCapturable = 1;
if (WinQueryFocus(HWND_DESKTOP) == _this->hidden->hwndClient)
{
WinSetCapture(HWND_DESKTOP, _this->hidden->hwndClient);
bMouseCaptured = 1;
{
SWP swpClient;
POINTL ptl;
// Center the mouse to the middle of the window!
WinQueryWindowPos(_this->hidden->hwndClient, &swpClient);
ptl.x = 0; ptl.y = 0;
WinMapWindowPoints(_this->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
_this->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account! */
WinSetPointerPos(HWND_DESKTOP,
ptl.x + swpClient.cx/2,
ptl.y + swpClient.cy/2);
}
}
}
// Now destroy the message queue, if we've created it!
if (ERRORIDERROR(hmqerror)==0)
WinDestroyMsgQueue(hmq);
return mode;
}
/* Set the title and icon text */
static void os2fslib_SetCaption(_THIS, const char *title, const char *icon)
{
HAB hab;
HMQ hmq;
ERRORID hmqerror;
// If there is no more window, nothing we can do!
if (_this->hidden->iPMThreadStatus!=1) return;
// Make sure this thread is prepared for using the Presentation Manager!
hab = WinInitialize(0);
hmq = WinCreateMsgQueue(hab,0);
// Remember if there was an error at WinCreateMsgQueue(), because we don't
// want to destroy somebody else's queue later. :)
hmqerror = WinGetLastError(hab);
WinSetWindowText(_this->hidden->hwndFrame, (char *) title);
// Now destroy the message queue, if we've created it!
if (ERRORIDERROR(hmqerror)==0)
WinDestroyMsgQueue(hmq);
}
static int os2fslib_ToggleFullScreen(_THIS, int on)
{
#ifdef DEBUG_BUILD
printf("[os2fslib_ToggleFullScreen] : %d\n", on); fflush(stdout);
#endif
// If there is no more window, nothing we can do!
if (_this->hidden->iPMThreadStatus!=1) return 0;
FSLib_ToggleFSMode(_this->hidden->hwndClient, on);
/* Cursor manager functions to Windowed/FS mode*/
os2fslib_SetCursorManagementFunctions(_this, !on);
return 1;
}
/* This is called after the video mode has been set, to get the
initial mouse state. It should queue events as necessary to
properly represent the current mouse focus and position.
*/
static void os2fslib_UpdateMouse(_THIS)
{
POINTL ptl;
HAB hab;
HMQ hmq;
ERRORID hmqerror;
SWP swpClient;
// If there is no more window, nothing we can do!
if (_this->hidden->iPMThreadStatus!=1) return;
// Make sure this thread is prepared for using the Presentation Manager!
hab = WinInitialize(0);
hmq = WinCreateMsgQueue(hab,0);
// Remember if there was an error at WinCreateMsgQueue(), because we don't
// want to destroy somebody else's queue later. :)
hmqerror = WinGetLastError(hab);
if (_this->hidden->fInFocus)
{
// If our app is in focus
SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS);
SDL_PrivateAppActive(1, SDL_APPACTIVE);
WinQueryPointerPos(HWND_DESKTOP, &ptl);
WinMapWindowPoints(HWND_DESKTOP, _this->hidden->hwndClient, &ptl, 1);
WinQueryWindowPos(_this->hidden->hwndClient, &swpClient);
// Convert OS/2 mouse position to SDL position, and also scale it!
ptl.x = ptl.x * _this->hidden->SrcBufferDesc.uiXResolution / swpClient.cx;
ptl.y = ptl.y * _this->hidden->SrcBufferDesc.uiYResolution / swpClient.cy;
ptl.y = _this->hidden->SrcBufferDesc.uiYResolution - ptl.y - 1;
SDL_PrivateMouseMotion(0, 0, (Sint16) (ptl.x), (Sint16) (ptl.y));
} else
{
// If we're not in focus
SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS);
SDL_PrivateAppActive(0, SDL_APPACTIVE);
SDL_PrivateMouseMotion(0, 0, (Sint16) -1, (Sint16) -1);
}
// Now destroy the message queue, if we've created it!
if (ERRORIDERROR(hmqerror)==0)
WinDestroyMsgQueue(hmq);
}
/* This pointer should exist in the native video subsystem and should
point to an appropriate update function for the current video mode
*/
static void os2fslib_UpdateRects(_THIS, int numrects, SDL_Rect *rects)
{
// If there is no more window, nothing we can do!
if (_this->hidden->iPMThreadStatus!=1) return;
#ifdef BITBLT_IN_WINMESSAGEPROC
WinSendMsg(_this->hidden->hwndClient,
WM_UPDATERECTSREQUEST,
(MPARAM) numrects,
(MPARAM) rects);
#else
if (DosRequestMutexSem(_this->hidden->hmtxUseSrcBuffer, SEM_INDEFINITE_WAIT)==NO_ERROR)
{
int i;
if (_this->hidden->pSDLSurface)
{
#ifndef RESIZE_EVEN_IF_RESIZABLE
SWP swp;
// But only blit if the window is not resizable, or if
// the window is resizable and the source buffer size is the
// same as the destination buffer size!
WinQueryWindowPos(_this->hidden->hwndClient, &swp);
if ((_this->hidden->pSDLSurface) &&
(_this->hidden->pSDLSurface->flags & SDL_RESIZABLE) &&
((swp.cx != _this->hidden->SrcBufferDesc.uiXResolution) ||
(swp.cy != _this->hidden->SrcBufferDesc.uiYResolution)
) &&
(!FSLib_QueryFSMode(_this->hidden->hwndClient))
)
{
// Resizable surface and in resizing!
// So, don't blit now!
#ifdef DEBUG_BUILD
printf("[UpdateRects] : Skipping blit while resizing!\n"); fflush(stdout);
#endif
} else
#endif
{
/*
// Blit the whole window
FSLIB_BITBLT(_this->hidden->hwndClient, _this->hidden->pchSrcBuffer,
0, 0,
_this->hidden->SrcBufferDesc.uiXResolution,
_this->hidden->SrcBufferDesc.uiYResolution);
*/
#ifdef DEBUG_BUILD
printf("[os2fslib_UpdateRects] : Blitting!\n"); fflush(stdout);
#endif
// Blit the changed areas
for (i=0; i<numrects; i++)
FSLIB_BITBLT(_this->hidden->hwndClient, _this->hidden->pchSrcBuffer,
rects[i].y, rects[i].x, rects[i].w, rects[i].h);
}
}
#ifdef DEBUG_BUILD
else
printf("[os2fslib_UpdateRects] : No public surface!\n"); fflush(stdout);
#endif
DosReleaseMutexSem(_this->hidden->hmtxUseSrcBuffer);
}
#ifdef DEBUG_BUILD
else
printf("[os2fslib_UpdateRects] : Error in mutex!\n"); fflush(stdout);
#endif
#endif
}
/* Reverse the effects VideoInit() -- called if VideoInit() fails
or if the application is shutting down the video subsystem.
*/
static void os2fslib_VideoQuit(_THIS)
{
#ifdef DEBUG_BUILD
printf("[os2fslib_VideoQuit]\n"); fflush(stdout);
#endif
// Close PM stuff if running!
if (_this->hidden->iPMThreadStatus == 1)
{
int iTimeout;
WinPostMsg(_this->hidden->hwndFrame, WM_QUIT, (MPARAM) 0, (MPARAM) 0);
// HACK: We had this line before:
//DosWaitThread((TID *) &(_this->hidden->tidPMThread), DCWW_WAIT);
// We don't use it, because the PMThread will never stop, or if it stops,
// it will kill the whole process as a emergency fallback.
// So, we only check for the iPMThreadStatus stuff!
#ifdef DEBUG_BUILD
printf("[os2fslib_VideoQuit] : Waiting for PM thread to die\n"); fflush(stdout);
#endif
iTimeout=0;
while ((_this->hidden->iPMThreadStatus == 1) && (iTimeout<100))
{
iTimeout++;
DosSleep(64);
}
#ifdef DEBUG_BUILD
printf("[os2fslib_VideoQuit] : End of wait.\n"); fflush(stdout);
#endif
if (_this->hidden->iPMThreadStatus == 1)
{
#ifdef DEBUG_BUILD
printf("[os2fslib_VideoQuit] : Killing PM thread!\n"); fflush(stdout);
#endif
_this->hidden->iPMThreadStatus = 0;
DosKillThread(_this->hidden->tidPMThread);
if (_this->hidden->hwndFrame)
{
#ifdef DEBUG_BUILD
printf("[os2fslib_VideoQuit] : Destroying PM window!\n"); fflush(stdout);
#endif
WinDestroyWindow(_this->hidden->hwndFrame); _this->hidden->hwndFrame=NULL;
}
}
}
// Free result of an old ListModes() call, because there is
// no FreeListModes() call in SDL!
if (_this->hidden->pListModesResult)
{
free(_this->hidden->pListModesResult); _this->hidden->pListModesResult = NULL;
}
// Free list of available fullscreen modes
if (_this->hidden->pAvailableFSLibVideoModes)
{
FSLib_FreeVideoModeList(_this->hidden->pAvailableFSLibVideoModes);
_this->hidden->pAvailableFSLibVideoModes = NULL;
}
// Free application icon if we had one
if (hptrCurrentIcon)
{
WinDestroyPointer(hptrCurrentIcon);
hptrCurrentIcon = NULL;
}
}
/* Set the requested video mode, returning a surface which will be
set to the SDL_VideoSurface. The width and height will already
be verified by ListModes(), and the video subsystem is free to
set the mode to a supported bit depth different from the one
specified -- the desired bpp will be emulated with a shadow
surface if necessary. If a new mode is returned, this function
should take care of cleaning up the current mode.
*/
static SDL_Surface *os2fslib_SetVideoMode(_THIS, SDL_Surface *current,
int width, int height, int bpp, Uint32 flags)
{
static int bFirstCall = 1;
FSLib_VideoMode_p pModeInfo, pModeInfoFound;
FSLib_VideoMode TempModeInfo;
HAB hab;
HMQ hmq;
ERRORID hmqerror;
RECTL rectl;
SDL_Surface *pResult;
// If there is no more window, nothing we can do!
if (_this->hidden->iPMThreadStatus!=1) return NULL;
#ifdef DEBUG_BUILD
printf("[os2fslib_SetVideoMode] : Request for %dx%d @ %dBPP, flags=0x%x\n", width, height, bpp, flags); fflush(stdout);
#endif
// We don't support palette modes!
if (bpp==8) bpp=32;
// Also, we don't support resizable modes in fullscreen mode.
if (flags & SDL_RESIZABLE)
flags &= ~SDL_FULLSCREEN;
// No double buffered mode
if (flags & SDL_DOUBLEBUF)
flags &= ~SDL_DOUBLEBUF;
// And, we don't support HWSURFACE yet.
if (flags & SDL_HWSURFACE)
{
flags &= ~SDL_HWSURFACE;
flags |= SDL_SWSURFACE;
}
#ifdef DEBUG_BUILD
printf("[os2fslib_SetVideoMode] : Changed request to %dx%d @ %dBPP, flags=0x%x\n", width, height, bpp, flags); fflush(stdout);
#endif
// First check if there is such a video mode they want!
pModeInfoFound = NULL;
// For fullscreen mode we don't support every resolution!
// So, go through the video modes, and check for such a resolution!
pModeInfoFound = NULL;
pModeInfo = _this->hidden->pAvailableFSLibVideoModes;
while (pModeInfo)
{
// Check all available fullscreen modes for this resolution
if ((pModeInfo->uiXResolution == width) &&
(pModeInfo->uiYResolution == height) &&
(pModeInfo->uiBPP!=8)) // palettized modes not yet supported
{
// If good resolution, try to find the exact BPP, or at least
// something similar...
if (!pModeInfoFound)
pModeInfoFound = pModeInfo;
else
if ((pModeInfoFound->uiBPP!=bpp) &&
(pModeInfoFound->uiBPP<pModeInfo->uiBPP))
pModeInfoFound = pModeInfo;
}
pModeInfo = pModeInfo->pNext;
}
// If we did not find a good fullscreen mode, then try a similar
if (!pModeInfoFound)
{
#ifdef DEBUG_BUILD
printf("[os2fslib_SetVideoMode] : Requested video mode not found, looking for a similar one!\n"); fflush(stdout);
#endif
// Go through the video modes again, and find a similar resolution!
pModeInfo = _this->hidden->pAvailableFSLibVideoModes;
while (pModeInfo)
{
// Check all available fullscreen modes for this resolution
if ((pModeInfo->uiXResolution >= width) &&
(pModeInfo->uiYResolution >= height) &&
(pModeInfo->uiBPP == bpp))
{
if (!pModeInfoFound)
pModeInfoFound = pModeInfo;
else
if (((pModeInfoFound->uiXResolution-width)*(pModeInfoFound->uiYResolution-height))>
((pModeInfo->uiXResolution-width)*(pModeInfo->uiYResolution-height)))
{
// Found a mode which is closer than the current one
pModeInfoFound = pModeInfo;
}
}
pModeInfo = pModeInfo->pNext;
}
}
// If we did not find a good fullscreen mode, then return NULL
if (!pModeInfoFound)
{
#ifdef DEBUG_BUILD
printf("[os2fslib_SetVideoMode] : Requested video mode not found!\n"); fflush(stdout);
#endif
return NULL;
}
#ifdef DEBUG_BUILD
printf("[os2fslib_SetVideoMode] : Found mode!\n"); fflush(stdout);
#endif
// We'll possibly adjust the structure, so copy out the values
// into TempModeInfo!
memcpy(&TempModeInfo, pModeInfoFound, sizeof(TempModeInfo));
pModeInfoFound = &TempModeInfo;
if (flags & SDL_RESIZABLE)
{
#ifdef DEBUG_BUILD
printf("[os2fslib_SetVideoMode] : Requested mode is resizable, changing width/height\n"); fflush(stdout);
#endif
// Change width and height to requested one!
TempModeInfo.uiXResolution = width;
TempModeInfo.uiYResolution = height;
TempModeInfo.uiScanLineSize = width * ((TempModeInfo.uiBPP+7)/8);
}
// We can try create new surface!
// Make sure this thread is prepared for using the Presentation Manager!
hab = WinInitialize(0);
hmq = WinCreateMsgQueue(hab,0);
// Remember if there was an error at WinCreateMsgQueue(), because we don't
// want to destroy somebody else's queue later. :)
hmqerror = WinGetLastError(hab);
if (DosRequestMutexSem(_this->hidden->hmtxUseSrcBuffer, SEM_INDEFINITE_WAIT)==NO_ERROR)
{
#ifdef DEBUG_BUILD
printf("[os2fslib_SetVideoMode] : Creating new SW surface\n"); fflush(stdout);
#endif
// Create new software surface!
pResult = SDL_CreateRGBSurface(SDL_SWSURFACE,
pModeInfoFound->uiXResolution,
pModeInfoFound->uiYResolution,
pModeInfoFound->uiBPP,
((unsigned int) pModeInfoFound->PixelFormat.ucRedMask) << pModeInfoFound->PixelFormat.ucRedPosition,
((unsigned int) pModeInfoFound->PixelFormat.ucGreenMask) << pModeInfoFound->PixelFormat.ucGreenPosition,
((unsigned int) pModeInfoFound->PixelFormat.ucBlueMask) << pModeInfoFound->PixelFormat.ucBluePosition,
((unsigned int) pModeInfoFound->PixelFormat.ucAlphaMask) << pModeInfoFound->PixelFormat.ucAlphaPosition);
if (pResult == NULL)
{
DosReleaseMutexSem(_this->hidden->hmtxUseSrcBuffer);
SDL_OutOfMemory();
return NULL;
}
#ifdef DEBUG_BUILD
printf("[os2fslib_SetVideoMode] : Adjusting pixel format\n"); fflush(stdout);
#endif
// Adjust pixel format mask!
pResult->format->Rmask = ((unsigned int) pModeInfoFound->PixelFormat.ucRedMask) << pModeInfoFound->PixelFormat.ucRedPosition;
pResult->format->Rshift = pModeInfoFound->PixelFormat.ucRedPosition;
pResult->format->Rloss = pModeInfoFound->PixelFormat.ucRedAdjust;
pResult->format->Gmask = ((unsigned int) pModeInfoFound->PixelFormat.ucGreenMask) << pModeInfoFound->PixelFormat.ucGreenPosition;
pResult->format->Gshift = pModeInfoFound->PixelFormat.ucGreenPosition;
pResult->format->Gloss = pModeInfoFound->PixelFormat.ucGreenAdjust;
pResult->format->Bmask = ((unsigned int) pModeInfoFound->PixelFormat.ucBlueMask) << pModeInfoFound->PixelFormat.ucBluePosition;
pResult->format->Bshift = pModeInfoFound->PixelFormat.ucBluePosition;
pResult->format->Bloss = pModeInfoFound->PixelFormat.ucBlueAdjust;
pResult->format->Amask = ((unsigned int) pModeInfoFound->PixelFormat.ucAlphaMask) << pModeInfoFound->PixelFormat.ucAlphaPosition;
pResult->format->Ashift = pModeInfoFound->PixelFormat.ucAlphaPosition;
pResult->format->Aloss = pModeInfoFound->PixelFormat.ucAlphaAdjust;
#ifdef REPORT_EMPTY_ALPHA_MASK
pResult->format->Amask =
pResult->format->Ashift =
pResult->format->Aloss = 0;
#endif
// Adjust surface flags
pResult->flags |= (flags & SDL_FULLSCREEN);
pResult->flags |= (flags & SDL_RESIZABLE);
// It might be that the software surface pitch is not the same as
// the pitch we have, so adjust that!
pModeInfoFound->uiScanLineSize = pResult->pitch;
// Store new source buffer parameters!
memcpy(&(_this->hidden->SrcBufferDesc), pModeInfoFound, sizeof(*pModeInfoFound));
_this->hidden->pchSrcBuffer = pResult->pixels;
#ifdef DEBUG_BUILD
printf("[os2fslib_SetVideoMode] : Telling FSLib the stuffs\n"); fflush(stdout);
#endif
// Tell the FSLib window the new source image format
FSLib_SetSrcBufferDesc(_this->hidden->hwndClient, &(_this->hidden->SrcBufferDesc));
if (
((flags & SDL_RESIZABLE)==0) ||
(bFirstCall)
)
{
bFirstCall = 0;
#ifdef DEBUG_BUILD
printf("[os2fslib_SetVideoMode] : Modifying window size\n"); fflush(stdout);
#endif
// Calculate frame window size from client window size
rectl.xLeft = 0;
rectl.yBottom = 0;
rectl.xRight = pModeInfoFound->uiXResolution; // Noninclusive
rectl.yTop = pModeInfoFound->uiYResolution; // Noninclusive
WinCalcFrameRect(_this->hidden->hwndFrame, &rectl, FALSE);
// Set the new size of the main window
SetAccessableWindowPos(_this->hidden->hwndFrame,
HWND_TOP,
0, 0,
(rectl.xRight-rectl.xLeft),
(rectl.yTop-rectl.yBottom),
SWP_SIZE | SWP_ACTIVATE | SWP_SHOW);
}
// Set fullscreen mode flag, and switch to fullscreen if needed!
if (flags & SDL_FULLSCREEN)
{
#ifdef DEBUG_BUILD
printf("[os2fslib_SetVideoMode] : Also trying to switch to fullscreen\n");
fflush(stdout);
#endif
FSLib_ToggleFSMode(_this->hidden->hwndClient, 1);
/* Cursor manager functions to FS mode*/
os2fslib_SetCursorManagementFunctions(_this, 0);
} else
{
#ifdef DEBUG_BUILD
printf("[os2fslib_SetVideoMode] : Also trying to switch to desktop mode\n");
fflush(stdout);
#endif
FSLib_ToggleFSMode(_this->hidden->hwndClient, 0);
/* Cursor manager functions to Windowed mode*/
os2fslib_SetCursorManagementFunctions(_this, 1);
}
_this->hidden->pSDLSurface = pResult;
DosReleaseMutexSem(_this->hidden->hmtxUseSrcBuffer);
} else
{
#ifdef DEBUG_BUILD
printf("[os2fslib_SetVideoMode] : Could not get hmtxUseSrcBuffer!\n"); fflush(stdout);
#endif
pResult = NULL;
}
// As we have the new surface, we don't need the current one anymore!
if ((pResult) && (current))
{
#ifdef DEBUG_BUILD
printf("[os2fslib_SetVideoMode] : Freeing old surface\n"); fflush(stdout);
#endif
SDL_FreeSurface(current);
}
// Redraw window
WinInvalidateRegion(_this->hidden->hwndClient, NULL, TRUE);
// Now destroy the message queue, if we've created it!
if (ERRORIDERROR(hmqerror)==0)
{
#ifdef DEBUG_BUILD
printf("[os2fslib_SetVideoMode] : Destroying message queue\n"); fflush(stdout);
#endif
WinDestroyMsgQueue(hmq);
}
#ifdef DEBUG_BUILD
printf("[os2fslib_SetVideoMode] : Done\n"); fflush(stdout);
#endif
/* We're done */
// Return with the new surface!
return pResult;
}
/* List the available video modes for the given pixel format, sorted
from largest to smallest.
*/
static SDL_Rect **os2fslib_ListModes(_THIS, SDL_PixelFormat *format, Uint32 flags)
{
#ifdef DEBUG_BUILD
printf("[os2fslib_ListModes] : ListModes of %d Bpp\n", format->BitsPerPixel);
#endif
// Destroy result of previous call, if there is any
if (_this->hidden->pListModesResult)
{
free(_this->hidden->pListModesResult); _this->hidden->pListModesResult = NULL;
}
// For resizable and windowed mode we support every resolution!
if ((flags & SDL_RESIZABLE) && ((flags & SDL_FULLSCREEN) == 0))
return (SDL_Rect **)-1;
// Check if they need fullscreen or non-fullscreen video modes!
if ((flags & SDL_FULLSCREEN) == 0)
{
// For windowed mode we support every resolution!
return (SDL_Rect **)-1;
} else
{
FSLib_VideoMode_p pFSMode;
// For fullscreen mode we don't support every resolution!
// Now create a new list
pFSMode = _this->hidden->pAvailableFSLibVideoModes;
while (pFSMode)
{
if (pFSMode->uiBPP == format->BitsPerPixel)
{
SDL_Rect *pRect = (SDL_Rect *) malloc(sizeof(SDL_Rect));
if (pRect)
{
// Fill description
pRect->x = 0;
pRect->y = 0;
pRect->w = pFSMode->uiXResolution;
pRect->h = pFSMode->uiYResolution;
#ifdef DEBUG_BUILD
// printf("!!! Seems to be good!\n");
// printf("F: %dx%d\n", pRect->w, pRect->h);
#endif
// And insert into list of pRects
if (!(_this->hidden->pListModesResult))
{
#ifdef DEBUG_BUILD
// printf("!!! Inserting to beginning\n");
#endif
// We're the first one to be inserted!
_this->hidden->pListModesResult = (SDL_Rect**) malloc(2*sizeof(SDL_Rect*));
if (_this->hidden->pListModesResult)
{
_this->hidden->pListModesResult[0] = pRect;
_this->hidden->pListModesResult[1] = NULL;
} else
{
free(pRect);
}
} else
{
// We're not the first ones, so find the place where we
// have to insert ourselves
SDL_Rect **pNewList;
int iPlace, iNumOfSlots, i;
#ifdef DEBUG_BUILD
// printf("!!! Searching where to insert\n");
#endif
iPlace = -1; iNumOfSlots = 1; // Count the last NULL too!
for (i=0; _this->hidden->pListModesResult[i]; i++)
{
iNumOfSlots++;
if (iPlace==-1)
{
if ((_this->hidden->pListModesResult[i]->w*_this->hidden->pListModesResult[i]->h)<
(pRect->w*pRect->h))
{
iPlace = i;
}
}
}
if (iPlace==-1) iPlace = iNumOfSlots-1;
#ifdef DEBUG_BUILD
// printf("!!! From %d slots, it will be at %d\n", iNumOfSlots, iPlace);
#endif
pNewList = (SDL_Rect**) realloc(_this->hidden->pListModesResult, (iNumOfSlots+1)*sizeof(SDL_Rect*));
if (pNewList)
{
for (i=iNumOfSlots;i>iPlace;i--)
pNewList[i] = pNewList[i-1];
pNewList[iPlace] = pRect;
_this->hidden->pListModesResult = pNewList;
} else
{
free(pRect);
}
}
}
}
pFSMode = pFSMode->pNext;
}
}
#ifdef DEBUG_BUILD
// printf("Returning list\n");
#endif
return _this->hidden->pListModesResult;
}
/* Initialize the native video subsystem, filling 'vformat' with the
"best" display pixel format, returning 0 or -1 if there's an error.
*/
static int os2fslib_VideoInit(_THIS, SDL_PixelFormat *vformat)
{
FSLib_VideoMode_p pDesktopMode;
#ifdef DEBUG_BUILD
printf("[os2fslib_VideoInit] : Enter\n"); fflush(stdout);
#endif
// Report the best pixel format. For this,
// we'll use the current desktop format.
pDesktopMode = FSLib_GetDesktopVideoMode();
if (!pDesktopMode)
{
SDL_SetError("Could not query desktop video mode!");
#ifdef DEBUG_BUILD
printf("[os2fslib_VideoInit] : Could not query desktop video mode!\n");
#endif
return -1;
}
/* Determine the screen depth */
vformat->BitsPerPixel = pDesktopMode->uiBPP;
vformat->BytesPerPixel = (vformat->BitsPerPixel+7)/8;
vformat->Rmask = ((unsigned int) pDesktopMode->PixelFormat.ucRedMask) << pDesktopMode->PixelFormat.ucRedPosition;
vformat->Rshift = pDesktopMode->PixelFormat.ucRedPosition;
vformat->Rloss = pDesktopMode->PixelFormat.ucRedAdjust;
vformat->Gmask = ((unsigned int) pDesktopMode->PixelFormat.ucGreenMask) << pDesktopMode->PixelFormat.ucGreenPosition;
vformat->Gshift = pDesktopMode->PixelFormat.ucGreenPosition;
vformat->Gloss = pDesktopMode->PixelFormat.ucGreenAdjust;
vformat->Bmask = ((unsigned int) pDesktopMode->PixelFormat.ucBlueMask) << pDesktopMode->PixelFormat.ucBluePosition;
vformat->Bshift = pDesktopMode->PixelFormat.ucBluePosition;
vformat->Bloss = pDesktopMode->PixelFormat.ucBlueAdjust;
vformat->Amask = ((unsigned int) pDesktopMode->PixelFormat.ucAlphaMask) << pDesktopMode->PixelFormat.ucAlphaPosition;
vformat->Ashift = pDesktopMode->PixelFormat.ucAlphaPosition;
vformat->Aloss = pDesktopMode->PixelFormat.ucAlphaAdjust;
#ifdef REPORT_EMPTY_ALPHA_MASK
vformat->Amask =
vformat->Ashift =
vformat->Aloss = 0;
#endif
// Fill in some window manager capabilities
_this->info.wm_available = 1;
// Initialize some internal variables
_this->hidden->pListModesResult = NULL;
_this->hidden->fInFocus = 0;
_this->hidden->iSkipWMMOUSEMOVE = 0;
_this->hidden->iMouseVisible = 1;
DosCreateMutexSem(NULL, &(_this->hidden->hmtxUseSrcBuffer), 0, FALSE);
// Now create our window with a default size
// For this, we select the first available fullscreen mode as
// current window size!
memcpy(&(_this->hidden->SrcBufferDesc), _this->hidden->pAvailableFSLibVideoModes, sizeof(_this->hidden->SrcBufferDesc));
// Allocate new video buffer!
_this->hidden->pchSrcBuffer = (char *) malloc(_this->hidden->pAvailableFSLibVideoModes->uiScanLineSize * _this->hidden->pAvailableFSLibVideoModes->uiYResolution);
if (!_this->hidden->pchSrcBuffer)
{
#ifdef DEBUG_BUILD
printf("[os2fslib_VideoInit] : Yikes, not enough memory for new video buffer!\n"); fflush(stdout);
#endif
SDL_SetError("Not enough memory for new video buffer!\n");
return -1;
}
// For this, we need a message processing thread.
// We'll create a new thread for this, which will do everything
// what is related to PM
_this->hidden->iPMThreadStatus = 0;
_this->hidden->tidPMThread = _beginthread(PMThreadFunc, NULL, 65536, (void *) _this);
if (_this->hidden->tidPMThread <= 0)
{
#ifdef DEBUG_BUILD
printf("[os2fslib_VideoInit] : Could not create PM thread!\n");
#endif
SDL_SetError("Could not create PM thread");
return -1;
}
#ifdef USE_DOSSETPRIORITY
// Burst the priority of PM Thread!
DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, _this->hidden->tidPMThread);
#endif
// Wait for the PM thread to initialize!
while (_this->hidden->iPMThreadStatus==0)
DosSleep(32);
// If the PM thread could not set up everything, then
// report an error!
if (_this->hidden->iPMThreadStatus!=1)
{
#ifdef DEBUG_BUILD
printf("[os2fslib_VideoInit] : PMThread reported an error : %d\n", _this->hidden->iPMThreadStatus);
#endif
SDL_SetError("Error initializing PM thread");
return -1;
}
return 0;
}
static void os2fslib_DeleteDevice(_THIS)
{
#ifdef DEBUG_BUILD
printf("[os2fslib_DeleteDevice]\n"); fflush(stdout);
#endif
// Free used memory
FSLib_FreeVideoModeList(_this->hidden->pAvailableFSLibVideoModes);
if (_this->hidden->pListModesResult)
free(_this->hidden->pListModesResult);
if (_this->hidden->pchSrcBuffer)
free(_this->hidden->pchSrcBuffer);
DosCloseMutexSem(_this->hidden->hmtxUseSrcBuffer);
free(_this->hidden);
free(_this);
FSLib_Uninitialize();
}
static int os2fslib_Available(void)
{
// If we can run, it means that we could load FSLib,
// so we assume that it's available then!
return 1;
}
static void os2fslib_MorphToPM()
{
PPIB pib;
PTIB tib;
DosGetInfoBlocks(&tib, &pib);
// Change flag from VIO to PM:
if (pib->pib_ultype==2) pib->pib_ultype = 3;
}
static SDL_VideoDevice *os2fslib_CreateDevice(int devindex)
{
SDL_VideoDevice *device;
#ifdef DEBUG_BUILD
printf("[os2fslib_CreateDevice] : Enter\n"); fflush(stdout);
#endif
/* Initialize all variables that we clean on shutdown */
device = (SDL_VideoDevice *)malloc(sizeof(SDL_VideoDevice));
if ( device )
{
memset(device, 0, (sizeof *device));
// Also allocate memory for private data
device->hidden = (struct SDL_PrivateVideoData *) malloc((sizeof(struct SDL_PrivateVideoData)));
}
if ( (device == NULL) || (device->hidden == NULL) )
{
SDL_OutOfMemory();
if ( device )
free(device);
return NULL;
}
memset(device->hidden, 0, (sizeof *device->hidden));
/* Set the function pointers */
#ifdef DEBUG_BUILD
printf("[os2fslib_CreateDevice] : VideoInit is %p\n", os2fslib_VideoInit); fflush(stdout);
#endif
/* Initialization/Query functions */
device->VideoInit = os2fslib_VideoInit;
device->ListModes = os2fslib_ListModes;
device->SetVideoMode = os2fslib_SetVideoMode;
device->ToggleFullScreen = os2fslib_ToggleFullScreen;
device->UpdateMouse = os2fslib_UpdateMouse;
device->CreateYUVOverlay = NULL;
device->SetColors = os2fslib_SetColors;
device->UpdateRects = os2fslib_UpdateRects;
device->VideoQuit = os2fslib_VideoQuit;
/* Hardware acceleration functions */
device->AllocHWSurface = os2fslib_AllocHWSurface;
device->CheckHWBlit = NULL;
device->FillHWRect = NULL;
device->SetHWColorKey = NULL;
device->SetHWAlpha = NULL;
device->LockHWSurface = os2fslib_LockHWSurface;
device->UnlockHWSurface = os2fslib_UnlockHWSurface;
device->FlipHWSurface = NULL;
device->FreeHWSurface = os2fslib_FreeHWSurface;
/* Window manager functions */
device->SetCaption = os2fslib_SetCaption;
device->SetIcon = os2fslib_SetIcon;
device->IconifyWindow = os2fslib_IconifyWindow;
device->GrabInput = os2fslib_GrabInput;
device->GetWMInfo = NULL;
/* Cursor manager functions to Windowed mode*/
os2fslib_SetCursorManagementFunctions(device, 1);
/* Event manager functions */
device->InitOSKeymap = os2fslib_InitOSKeymap;
device->PumpEvents = os2fslib_PumpEvents;
/* The function used to dispose of this structure */
device->free = os2fslib_DeleteDevice;
// Make sure we'll be able to use Win* API even if the application
// was linked to be a VIO application!
os2fslib_MorphToPM();
// Now initialize FSLib, and query available video modes!
if (!FSLib_Initialize())
{
// Could not initialize FSLib!
#ifdef DEBUG_BUILD
printf("[os2fslib_CreateDevice] : Could not initialize FSLib!\n");
#endif
SDL_SetError("Could not initialize FSLib!");
free(device->hidden);
free(device);
return NULL;
}
device->hidden->pAvailableFSLibVideoModes =
FSLib_GetVideoModeList();
return device;
}
VideoBootStrap OS2FSLib_bootstrap = {
"os2fslib", "OS/2 Video Output using FSLib",
os2fslib_Available, os2fslib_CreateDevice
};
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#ifndef _SDL_os2fslib_h
#define _SDL_os2fslib_h
// OS2 specific includes
#define INCL_TYPES
#define INCL_DOS
#define INCL_DOSERRORS
#define INCL_DOSPROCESS
#define INCL_WIN
#define INCL_GPI
#include <os2.h>
#include <FSLib.h>
/* Hidden "this" pointer for the video functions */
#define _THIS SDL_VideoDevice *_this
/* Private display data */
struct SDL_PrivateVideoData
{
FSLib_VideoMode_p pAvailableFSLibVideoModes;
SDL_Rect **pListModesResult; // Allocated memory to return list of modes for os2fslib_ListModes() API
FSLib_VideoMode SrcBufferDesc; // Description of current source image buffer
char *pchSrcBuffer; // The source image buffer itself
SDL_Surface *pSDLSurface; // The SDL surface describing the buffer
HMTX hmtxUseSrcBuffer; // Mutex semaphore to manipulate src buffer
HWND hwndFrame, hwndClient; // Window handle of frame and client
int iPMThreadStatus; // 0: Not running
// 1: Running
// Other: Not running, had an error
int tidPMThread; // Thread ID of PM Thread
int fInFocus; // True if we're in focus!
int iSkipWMMOUSEMOVE; // Number of WM_MOUSEMOVE messages to skip!
int iMouseVisible; //
};
extern DECLSPEC void SDLCALL SDL_OS2FSLIB_SetFCFToUse(ULONG ulFCF);
#endif /* _SDL_os2fslib_h */
/*
SDL - Simple DirectMedia Layer
Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002 Sam Lantinga
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Sam Lantinga
slouken@libsdl.org
*/
#ifdef SAVE_RCSID
static char rcsid =
"@(#) $Id$";
#endif
#ifndef VK_0
#define VK_0 '0'
#define VK_1 '1'
#define VK_2 '2'
#define VK_3 '3'
#define VK_4 '4'
#define VK_5 '5'
#define VK_6 '6'
#define VK_7 '7'
#define VK_8 '8'
#define VK_9 '9'
#define VK_A 'A'
#define VK_B 'B'
#define VK_C 'C'
#define VK_D 'D'
#define VK_E 'E'
#define VK_F 'F'
#define VK_G 'G'
#define VK_H 'H'
#define VK_I 'I'
#define VK_J 'J'
#define VK_K 'K'
#define VK_L 'L'
#define VK_M 'M'
#define VK_N 'N'
#define VK_O 'O'
#define VK_P 'P'
#define VK_Q 'Q'
#define VK_R 'R'
#define VK_S 'S'
#define VK_T 'T'
#define VK_U 'U'
#define VK_V 'V'
#define VK_W 'W'
#define VK_X 'X'
#define VK_Y 'Y'
#define VK_Z 'Z'
#endif /* VK_0 */
/* These keys haven't been defined, but were experimentally determined */
#define VK_SEMICOLON 0xBA
#define VK_EQUALS 0xBB
#define VK_COMMA 0xBC
#define VK_MINUS 0xBD
#define VK_PERIOD 0xBE
#define VK_SLASH 0xBF
#define VK_GRAVE 0xC0
#define VK_LBRACKET 0xDB
#define VK_BACKSLASH 0xDC
#define VK_RBRACKET 0xDD
#define VK_APOSTROPHE 0xDE
#define VK_BACKTICK 0xDF
#=============================================================================
# This is a Watcom makefile to build SDL.DLL for OS/2
#
# Makefile for test applications
#=============================================================================
# Create debug build or not?
debug_build=defined
#-----------------------------------------------------------------------------
# The next part is somewhat general, for creation of EXE files.
#-----------------------------------------------------------------------------
cflags = $(debugflags) -bm -bt=OS2 -5 -fpi -sg -otexan -wx -ei
.before
set include=$(%os2tk)\h;$(%include);../include
.extensions:
.extensions: .exe .obj .c
all : testalpha.exe &
testbitmap.exe &
testcdrom.exe &
testcpuinfo.exe &
testjoystick.exe &
testkeys.exe &
testlock.exe &
testsem.exe &
testsprite.exe &
testtimer.exe &
testtypes.exe &
testver.exe &
testvidinfo.exe &
testwin.exe &
testwm.exe &
threadwin.exe &
torturethread.exe &
checkkeys.exe
.c.obj : .AUTODEPEND
wcc386 -zq -bm -5s -ei -oteaxan -wx $[* $(cflags)
.obj.exe : .AUTODEPEND
wlink system os2v2 F $* L ..\src\sdl.lib name $@ op quiet
clean : .SYMBOLIC
@if exist *.exe del *.exe
@if exist *.obj del *.obj
@if exist *.map del *.map
@if exist *.res del *.res
@if exist *.lst del *.lst
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment