From b4b5899abe79b768e381a51e5b4ab783810abfd7 Mon Sep 17 00:00:00 2001 From: "Ryan C. Gordon" Date: Wed, 23 Nov 2005 07:29:56 +0000 Subject: [PATCH] OS/2 port! This was mostly, if not entirely, written by "Doodle" and "Caetano": doodle@scenergy.dfmk.hu daniel@caetano.eng.br --ryan. --- README.OS2 | 133 ++ Watcom.mif | 33 + include/SDL_byteorder.h | 5 +- include/SDL_thread.h | 43 + include/SDL_types.h | 2 +- include/begin_code.h | 18 + setvars.cmd | 16 + src/Makefile.wat | 132 ++ src/SDL.c | 87 + src/SDL_loadso.c | 2 + src/audio/Makefile.wat | 27 + src/audio/SDL_audio.c | 24 + src/audio/SDL_mixer_MMX_VC.c | 6 + src/audio/SDL_sysaudio.h | 3 + src/audio/dart/SDL_dart.c | 436 +++++ src/audio/dart/SDL_dart.h | 67 + src/cdrom/Makefile.wat | 30 + src/cdrom/os2/SDL_syscdrom.c | 399 ++++ src/cpuinfo/Makefile.wat | 27 + src/endian/Makefile.wat | 24 + src/events/Makefile.wat | 24 + src/events/SDL_events.c | 19 + src/events/SDL_resize.c | 7 +- src/events/SDL_sysevents.h | 4 + src/file/Makefile.wat | 24 + src/joystick/Makefile.wat | 27 + src/joystick/os2/SDL_sysjoystick.c | 669 +++++++ src/joystick/os2/joyos2.h | 177 ++ src/loadso/macosx/SDL_loadso.c | 1 + src/loadso/os2/SDL_loadso.c | 82 + src/thread/Makefile.wat | 36 + src/thread/SDL_systhread.h | 4 + src/thread/SDL_thread.c | 10 +- src/thread/os2/SDL_syscond.c | 223 +++ src/thread/os2/SDL_syscond_c.h | 27 + src/thread/os2/SDL_sysmutex.c | 115 ++ src/thread/os2/SDL_syssem.c | 199 ++ src/thread/os2/SDL_systhread.c | 114 ++ src/thread/os2/SDL_systhread_c.h | 27 + src/timer/Makefile.wat | 27 + src/timer/SDL_timer.c | 2 +- src/timer/os2/SDL_systimer.c | 230 +++ src/video/Makefile.wat | 27 + src/video/SDL_sysvideo.h | 3 + src/video/SDL_video.c | 6 + src/video/os2fslib/SDL_os2fslib.c | 2787 ++++++++++++++++++++++++++++ src/video/os2fslib/SDL_os2fslib.h | 63 + src/video/os2fslib/SDL_vkeys.h | 79 + test/Makefile.wat | 52 + 49 files changed, 6571 insertions(+), 8 deletions(-) create mode 100644 README.OS2 create mode 100644 Watcom.mif create mode 100644 setvars.cmd create mode 100644 src/Makefile.wat create mode 100644 src/audio/Makefile.wat create mode 100644 src/audio/dart/SDL_dart.c create mode 100644 src/audio/dart/SDL_dart.h create mode 100644 src/cdrom/Makefile.wat create mode 100644 src/cdrom/os2/SDL_syscdrom.c create mode 100644 src/cpuinfo/Makefile.wat create mode 100644 src/endian/Makefile.wat create mode 100644 src/events/Makefile.wat create mode 100644 src/file/Makefile.wat create mode 100644 src/joystick/Makefile.wat create mode 100644 src/joystick/os2/SDL_sysjoystick.c create mode 100644 src/joystick/os2/joyos2.h create mode 100644 src/loadso/os2/SDL_loadso.c create mode 100644 src/thread/Makefile.wat create mode 100644 src/thread/os2/SDL_syscond.c create mode 100644 src/thread/os2/SDL_syscond_c.h create mode 100644 src/thread/os2/SDL_sysmutex.c create mode 100644 src/thread/os2/SDL_syssem.c create mode 100644 src/thread/os2/SDL_systhread.c create mode 100644 src/thread/os2/SDL_systhread_c.h create mode 100644 src/timer/Makefile.wat create mode 100644 src/timer/os2/SDL_systimer.c create mode 100644 src/video/Makefile.wat create mode 100644 src/video/os2fslib/SDL_os2fslib.c create mode 100644 src/video/os2fslib/SDL_os2fslib.h create mode 100644 src/video/os2fslib/SDL_vkeys.h create mode 100644 test/Makefile.wat diff --git a/README.OS2 b/README.OS2 new file mode 100644 index 000000000..fc3e0b8a6 --- /dev/null +++ b/README.OS2 @@ -0,0 +1,133 @@ + +=========== +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! + diff --git a/Watcom.mif b/Watcom.mif new file mode 100644 index 000000000..350e31667 --- /dev/null +++ b/Watcom.mif @@ -0,0 +1,33 @@ +#============================================================================= +# 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 diff --git a/include/SDL_byteorder.h b/include/SDL_byteorder.h index b181dc8a1..4a7c46305 100644 --- a/include/SDL_byteorder.h +++ b/include/SDL_byteorder.h @@ -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 diff --git a/include/SDL_thread.h b/include/SDL_thread.h index abf81f273..7110e538e 100644 --- a/include/SDL_thread.h +++ b/include/SDL_thread.h @@ -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 // This has _beginthread() and _endthread() defined! +#endif +#ifdef __EMX__ +#include // 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); diff --git a/include/SDL_types.h b/include/SDL_types.h index 14bf1ec23..66ff0aec9 100644 --- a/include/SDL_types.h +++ b/include/SDL_types.h @@ -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 diff --git a/include/begin_code.h b/include/begin_code.h index 925d37909..78f22209a 100644 --- a/include/begin_code.h +++ b/include/begin_code.h @@ -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 */ diff --git a/setvars.cmd b/setvars.cmd new file mode 100644 index 000000000..b8c2071e3 --- /dev/null +++ b/setvars.cmd @@ -0,0 +1,16 @@ +@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 + diff --git a/src/Makefile.wat b/src/Makefile.wat new file mode 100644 index 000000000..476cfabbc --- /dev/null +++ b/src/Makefile.wat @@ -0,0 +1,132 @@ +#============================================================================= +# 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 .. diff --git a/src/SDL.c b/src/SDL.c index e4db3cc09..913c7c2d7 100644 --- a/src/SDL.c +++ b/src/SDL.c @@ -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 @@ -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 + +// 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 diff --git a/src/SDL_loadso.c b/src/SDL_loadso.c index 872db0c28..566c99eea 100644 --- a/src/SDL_loadso.c +++ b/src/SDL_loadso.c @@ -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 */ diff --git a/src/audio/Makefile.wat b/src/audio/Makefile.wat new file mode 100644 index 000000000..0a292be3c --- /dev/null +++ b/src/audio/Makefile.wat @@ -0,0 +1,27 @@ +#============================================================================= +# 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 diff --git a/src/audio/SDL_audio.c b/src/audio/SDL_audio.c index 7bbb1a0af..a9d77d5ca 100644 --- a/src/audio/SDL_audio.c +++ b/src/audio/SDL_audio.c @@ -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 +#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); } diff --git a/src/audio/SDL_mixer_MMX_VC.c b/src/audio/SDL_mixer_MMX_VC.c index 8516dd197..3229f62b7 100644 --- a/src/audio/SDL_mixer_MMX_VC.c +++ b/src/audio/SDL_mixer_MMX_VC.c @@ -12,8 +12,10 @@ // Mixing for 16 bit signed buffers //////////////////////////////////////////////// +#ifndef __WATCOMC__ #include #include +#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 diff --git a/src/audio/SDL_sysaudio.h b/src/audio/SDL_sysaudio.h index 0a5698446..beebe781a 100644 --- a/src/audio/SDL_sysaudio.h +++ b/src/audio/SDL_sysaudio.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; diff --git a/src/audio/dart/SDL_dart.c b/src/audio/dart/SDL_dart.c new file mode 100644 index 000000000..6a3915a0a --- /dev/null +++ b/src/audio/dart/SDL_dart.c @@ -0,0 +1,436 @@ +/* + 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 +#include +#include + +#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; ihidden->pMixBuffers[i].pBuffer)) || (!pBufferDesc)) + { // Wrong buffer! + // Close DART, and exit with error code! + // Free buffer descriptions + { int j; + for (j=0; jhidden->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; ihidden->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 +}; + diff --git a/src/audio/dart/SDL_dart.h b/src/audio/dart/SDL_dart.h new file mode 100644 index 000000000..b016f4732 --- /dev/null +++ b/src/audio/dart/SDL_dart.h @@ -0,0 +1,67 @@ +/* + 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 +#include // 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 */ diff --git a/src/cdrom/Makefile.wat b/src/cdrom/Makefile.wat new file mode 100644 index 000000000..bda64eb22 --- /dev/null +++ b/src/cdrom/Makefile.wat @@ -0,0 +1,30 @@ +#============================================================================= +# 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 diff --git a/src/cdrom/os2/SDL_syscdrom.c b/src/cdrom/os2/SDL_syscdrom.c new file mode 100644 index 000000000..f3e51bf15 --- /dev/null +++ b/src/cdrom/os2/SDL_syscdrom.c @@ -0,0 +1,399 @@ +/* + 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 +#include +#include +#include +#include + +#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; istatus == 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; inumtracks; 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 +#include +#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; diff --git a/src/events/SDL_resize.c b/src/events/SDL_resize.c index 64f986f6a..418a9c601 100644 --- a/src/events/SDL_resize.c +++ b/src/events/SDL_resize.c @@ -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; diff --git a/src/events/SDL_sysevents.h b/src/events/SDL_sysevents.h index ab66dcd0a..6422d95c3 100644 --- a/src/events/SDL_sysevents.h +++ b/src/events/SDL_sysevents.h @@ -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 diff --git a/src/file/Makefile.wat b/src/file/Makefile.wat new file mode 100644 index 000000000..93ee69152 --- /dev/null +++ b/src/file/Makefile.wat @@ -0,0 +1,24 @@ +#============================================================================= +# 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 diff --git a/src/joystick/Makefile.wat b/src/joystick/Makefile.wat new file mode 100644 index 000000000..098215d76 --- /dev/null +++ b/src/joystick/Makefile.wat @@ -0,0 +1,27 @@ +#============================================================================= +# 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 diff --git a/src/joystick/os2/SDL_sysjoystick.c b/src/joystick/os2/SDL_sysjoystick.c new file mode 100644 index 000000000..8938f0788 --- /dev/null +++ b/src/joystick/os2/SDL_sysjoystick.c @@ -0,0 +1,669 @@ +/* + 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 +#include +#include + +#define INCL_DOSDEVICES +#define INCL_DOSDEVIOCTL +#define INCL_DOSMEMMGR +#include +#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< 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; ilower; + 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; ihwdata = (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->nbuttonsnbuttons; +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; +} + + diff --git a/src/joystick/os2/joyos2.h b/src/joystick/os2/joyos2.h new file mode 100644 index 000000000..29800106e --- /dev/null +++ b/src/joystick/os2/joyos2.h @@ -0,0 +1,177 @@ +/*****************************************************************************/ +/* */ +/* 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 diff --git a/src/loadso/macosx/SDL_loadso.c b/src/loadso/macosx/SDL_loadso.c index d805dc027..a298aacd4 100644 --- a/src/loadso/macosx/SDL_loadso.c +++ b/src/loadso/macosx/SDL_loadso.c @@ -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) { diff --git a/src/loadso/os2/SDL_loadso.c b/src/loadso/os2/SDL_loadso.c new file mode 100644 index 000000000..aa8c7d0fc --- /dev/null +++ b/src/loadso/os2/SDL_loadso.c @@ -0,0 +1,82 @@ +/* + 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 +#define INCL_DOSERRORS +#define INCL_DOSMODULEMGR +#include + +#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); +} + diff --git a/src/thread/Makefile.wat b/src/thread/Makefile.wat new file mode 100644 index 000000000..a5de15012 --- /dev/null +++ b/src/thread/Makefile.wat @@ -0,0 +1,36 @@ +#============================================================================= +# 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 diff --git a/src/thread/SDL_systhread.h b/src/thread/SDL_systhread.h index ff1b71893..8b150d1e6 100644 --- a/src/thread/SDL_systhread.h +++ b/src/thread/SDL_systhread.h @@ -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); diff --git a/src/thread/SDL_thread.c b/src/thread/SDL_thread.c index 8a2e3ba6c..4d7008ee9 100644 --- a/src/thread/SDL_thread.c +++ b/src/thread/SDL_thread.c @@ -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); diff --git a/src/thread/os2/SDL_syscond.c b/src/thread/os2/SDL_syscond.c new file mode 100644 index 000000000..b1505bcab --- /dev/null +++ b/src/thread/os2/SDL_syscond.c @@ -0,0 +1,223 @@ +/* + 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 +#include + +#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; iwait_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; iwait_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); +} diff --git a/src/thread/os2/SDL_syscond_c.h b/src/thread/os2/SDL_syscond_c.h new file mode 100644 index 000000000..33585baf2 --- /dev/null +++ b/src/thread/os2/SDL_syscond_c.h @@ -0,0 +1,27 @@ +/* + 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 + diff --git a/src/thread/os2/SDL_sysmutex.c b/src/thread/os2/SDL_sysmutex.c new file mode 100644 index 000000000..bbbffdba2 --- /dev/null +++ b/src/thread/os2/SDL_sysmutex.c @@ -0,0 +1,115 @@ +/* + 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 +#include +#define INCL_DOSERRORS +#define INCL_DOSSEMAPHORES +#include + +#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); +} diff --git a/src/thread/os2/SDL_syssem.c b/src/thread/os2/SDL_syssem.c new file mode 100644 index 000000000..f455db093 --- /dev/null +++ b/src/thread/os2/SDL_syssem.c @@ -0,0 +1,199 @@ +/* + 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 +#include +#define INCL_DOS +#define INCL_DOSERRORS +#define INCL_DOSSEMAPHORES +#include + +#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; +} diff --git a/src/thread/os2/SDL_systhread.c b/src/thread/os2/SDL_systhread.c new file mode 100644 index 000000000..b29779c77 --- /dev/null +++ b/src/thread/os2/SDL_systhread.c @@ -0,0 +1,114 @@ +/* + 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 +#include +#include +#define INCL_DOSERRORS +#define INCL_DOSPROCESS +#include + +#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); +} diff --git a/src/thread/os2/SDL_systhread_c.h b/src/thread/os2/SDL_systhread_c.h new file mode 100644 index 000000000..e578f3b2b --- /dev/null +++ b/src/thread/os2/SDL_systhread_c.h @@ -0,0 +1,27 @@ +/* + 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 + +typedef TID SYS_ThreadHandle; + diff --git a/src/timer/Makefile.wat b/src/timer/Makefile.wat new file mode 100644 index 000000000..0858fbfa4 --- /dev/null +++ b/src/timer/Makefile.wat @@ -0,0 +1,27 @@ +#============================================================================= +# 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 diff --git a/src/timer/SDL_timer.c b/src/timer/SDL_timer.c index 239452794..ab6c09dfb 100644 --- a/src/timer/SDL_timer.c +++ b/src/timer/SDL_timer.c @@ -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); diff --git a/src/timer/os2/SDL_systimer.c b/src/timer/os2/SDL_systimer.c new file mode 100644 index 000000000..b11b7db95 --- /dev/null +++ b/src/timer/os2/SDL_systimer.c @@ -0,0 +1,230 @@ +/* + 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 + +#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; +} + + diff --git a/src/video/Makefile.wat b/src/video/Makefile.wat new file mode 100644 index 000000000..e2094c36e --- /dev/null +++ b/src/video/Makefile.wat @@ -0,0 +1,27 @@ +#============================================================================= +# 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 diff --git a/src/video/SDL_sysvideo.h b/src/video/SDL_sysvideo.h index a83d8a22f..730bf0730 100644 --- a/src/video/SDL_sysvideo.h +++ b/src/video/SDL_sysvideo.h @@ -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; diff --git a/src/video/SDL_video.c b/src/video/SDL_video.c index 66d110d62..2646bb1ee 100644 --- a/src/video/SDL_video.c +++ b/src/video/SDL_video.c @@ -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) ) { diff --git a/src/video/os2fslib/SDL_os2fslib.c b/src/video/os2fslib/SDL_os2fslib.c new file mode 100644 index 000000000..e013a62bb --- /dev/null +++ b/src/video/os2fslib/SDL_os2fslib.c @@ -0,0 +1,2787 @@ +/* + 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 +#include +#include +#include +#include + +#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; ihidden->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; ihptr = 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; yhidden->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; ihidden->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->uiBPPuiBPP)) + 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 +}; + diff --git a/src/video/os2fslib/SDL_os2fslib.h b/src/video/os2fslib/SDL_os2fslib.h new file mode 100644 index 000000000..86c1878b8 --- /dev/null +++ b/src/video/os2fslib/SDL_os2fslib.h @@ -0,0 +1,63 @@ +/* + 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 + +#include + +/* 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 */ diff --git a/src/video/os2fslib/SDL_vkeys.h b/src/video/os2fslib/SDL_vkeys.h new file mode 100644 index 000000000..7d19903ee --- /dev/null +++ b/src/video/os2fslib/SDL_vkeys.h @@ -0,0 +1,79 @@ +/* + 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 diff --git a/test/Makefile.wat b/test/Makefile.wat new file mode 100644 index 000000000..db09284e8 --- /dev/null +++ b/test/Makefile.wat @@ -0,0 +1,52 @@ +#============================================================================= +# 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