--HG-- extra : convert_revision : svn%3Ac70aab31-4412-0410-b14c-859654838e24/trunk%401446
3014 lines
94 KiB
C
3014 lines
94 KiB
C
/*
|
|
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 "SDL_config.h"
|
|
|
|
#define _ULS_CALLCONV_
|
|
#define CALLCONV _System
|
|
#include <unidef.h> // Unicode API
|
|
#include <uconv.h> // Unicode API (codepage conversion)
|
|
|
|
#include <process.h>
|
|
#include <time.h>
|
|
|
|
#include "SDL_video.h"
|
|
#include "SDL_mouse.h"
|
|
#include "../SDL_sysvideo.h"
|
|
#include "../SDL_pixels_c.h"
|
|
#include "../../events/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);
|
|
}
|
|
|
|
static UniChar NativeCharToUniChar(int chcode)
|
|
{
|
|
UniChar ucResult = (UniChar) chcode;
|
|
int rc;
|
|
UconvObject ucoTemp;
|
|
char achFrom[2];
|
|
char *pchFrom;
|
|
size_t iFromCount;
|
|
UniChar aucTo[10];
|
|
UniChar *pucTo;
|
|
size_t iToCount;
|
|
size_t iNonIdentical;
|
|
|
|
// Create unicode convert object
|
|
rc = UniCreateUconvObject(L"", &ucoTemp);
|
|
if (rc!=ULS_SUCCESS)
|
|
{
|
|
// Could not create convert object!
|
|
return ucResult;
|
|
}
|
|
|
|
// Convert language code string to unicode string
|
|
achFrom[0] = (char) chcode;
|
|
achFrom[1] = 0;
|
|
iFromCount = sizeof(char) * 2;
|
|
iToCount = sizeof(UniChar) * 2;
|
|
pucTo = &(aucTo[0]);
|
|
pchFrom = &(achFrom[0]);
|
|
|
|
rc = UniUconvToUcs(ucoTemp,
|
|
&pchFrom,
|
|
&iFromCount,
|
|
&pucTo,
|
|
&iToCount,
|
|
&iNonIdentical);
|
|
|
|
if (rc!=ULS_SUCCESS)
|
|
{
|
|
// Could not convert language code to UCS string!
|
|
UniFreeUconvObject(ucoTemp);
|
|
return ucResult;
|
|
}
|
|
|
|
UniFreeUconvObject(ucoTemp);
|
|
|
|
#ifdef DEBUG_BUILD
|
|
printf("%02x converted to %02x\n", (int) chcode, (int) (aucTo[0]));
|
|
#endif
|
|
|
|
return aucTo[0];
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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)
|
|
{
|
|
if (chcode)
|
|
keysym->unicode = NativeCharToUniChar(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;
|
|
|
|
if (bMouseCaptured)
|
|
{
|
|
SWP swpClient;
|
|
|
|
WinQueryWindowPos(pVideo->hidden->hwndClient, &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 - (swpClient.cx/2),
|
|
(swpClient.cy/2) - ppts->y);
|
|
|
|
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
|
|
{
|
|
CONVERTMOUSEPOSITION();
|
|
|
|
// Send absolute mouse position
|
|
SDL_PrivateMouseMotion(0, // Buttons not changed
|
|
0, // Absolute position
|
|
ppts->x,
|
|
ppts->y);
|
|
}
|
|
}
|
|
if ((pVideo->hidden->iMouseVisible) && (!bMouseCaptured))
|
|
{
|
|
#ifdef DEBUG_BUILD
|
|
// printf("WM_MOUSEMOVE : ptr = %p\n", hptrGlobalPointer); fflush(stdout);
|
|
#endif
|
|
|
|
if (hptrGlobalPointer)
|
|
WinSetPointer(HWND_DESKTOP, hptrGlobalPointer);
|
|
else
|
|
WinSetPointer(HWND_DESKTOP, WinQuerySysPointer(HWND_DESKTOP, SPTR_ARROW, FALSE));
|
|
}
|
|
else
|
|
{
|
|
WinSetPointer(HWND_DESKTOP, NULL);
|
|
}
|
|
}
|
|
#ifdef DEBUG_BUILD
|
|
// printf("WM_MOUSEMOVE done\n"); fflush(stdout);
|
|
#endif
|
|
|
|
return (MRESULT) FALSE;
|
|
case WM_CLOSE: // Window close
|
|
#ifdef DEBUG_BUILD
|
|
printf("WM_CLOSE\n"); fflush(stdout);
|
|
#endif
|
|
|
|
pVideo = FSLib_GetUserParm(hwnd);
|
|
if (pVideo)
|
|
{
|
|
// Send Quit message to the SDL application!
|
|
SDL_PrivateQuit();
|
|
return 0;
|
|
}
|
|
break;
|
|
|
|
#ifdef BITBLT_IN_WINMESSAGEPROC
|
|
case WM_UPDATERECTSREQUEST:
|
|
pVideo = FSLib_GetUserParm(hwnd);
|
|
if ((pVideo) && (pVideo->hidden->pSDLSurface))
|
|
{
|
|
if (DosRequestMutexSem(pVideo->hidden->hmtxUseSrcBuffer, SEM_INDEFINITE_WAIT)==NO_ERROR)
|
|
{
|
|
int numrects;
|
|
SDL_Rect *rects;
|
|
int i;
|
|
SWP swp;
|
|
|
|
numrects = (int) mp1;
|
|
rects = (SDL_Rect *) mp2;
|
|
|
|
WinQueryWindowPos(hwnd, &swp);
|
|
#ifndef RESIZE_EVEN_IF_RESIZABLE
|
|
if ((!pVideo->hidden->pSDLSurface) ||
|
|
(
|
|
(pVideo->hidden->pSDLSurface) &&
|
|
(pVideo->hidden->pSDLSurface->flags & SDL_RESIZABLE) &&
|
|
((swp.cx != pVideo->hidden->SrcBufferDesc.uiXResolution) ||
|
|
(swp.cy != pVideo->hidden->SrcBufferDesc.uiYResolution)
|
|
) &&
|
|
(!FSLib_QueryFSMode(hwnd))
|
|
)
|
|
)
|
|
{
|
|
// Resizable surface and in resizing!
|
|
// So, don't blit now!
|
|
#ifdef DEBUG_BUILD
|
|
printf("[WM_UPDATERECTSREQUEST] : Skipping blit while resizing!\n"); fflush(stdout);
|
|
#endif
|
|
} else
|
|
#endif
|
|
{
|
|
#ifdef DEBUG_BUILD
|
|
printf("[WM_UPDATERECTSREQUEST] : Blitting!\n"); fflush(stdout);
|
|
#endif
|
|
|
|
// Blit the changed areas
|
|
for (i=0; i<numrects; i++)
|
|
FSLIB_BITBLT(hwnd, pVideo->hidden->pchSrcBuffer,
|
|
rects[i].y, rects[i].x, rects[i].w, rects[i].h);
|
|
}
|
|
DosReleaseMutexSem(pVideo->hidden->hmtxUseSrcBuffer);
|
|
}
|
|
}
|
|
return 0;
|
|
#endif
|
|
|
|
default:
|
|
#ifdef DEBUG_BUILD
|
|
printf("Unhandled: %x\n", msg); fflush(stdout);
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
// Run the default window procedure for unhandled stuffs
|
|
return WinDefWindowProc(hwnd, msg, mp1, mp2);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// FrameWndProc
|
|
//
|
|
// This is the message processing window procedure for the
|
|
// frame window of SDLWindowClass.
|
|
//
|
|
/////////////////////////////////////////////////////////////////////
|
|
static MRESULT EXPENTRY FrameWndProc( HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
|
|
{
|
|
PFNWP pOldFrameProc;
|
|
MRESULT result;
|
|
PTRACKINFO ti;
|
|
int cx, cy, ncx, ncy;
|
|
RECTL rclTemp;
|
|
PSWP pswpTemp;
|
|
|
|
SDL_VideoDevice *pVideo = NULL;
|
|
|
|
pVideo = (SDL_VideoDevice *) WinQueryWindowULong(hwnd, QWL_USER);
|
|
|
|
pOldFrameProc = pVideo->hidden->pfnOldFrameProc;
|
|
|
|
if ((pVideo->hidden->bProportionalResize) &&
|
|
(msg==WM_ADJUSTWINDOWPOS) &&
|
|
(!FSLib_QueryFSMode(pVideo->hidden->hwndClient))
|
|
)
|
|
{
|
|
pswpTemp = (PSWP) mp1;
|
|
|
|
/* Resizing? */
|
|
if (pswpTemp->fl & SWP_SIZE)
|
|
{
|
|
/* Calculate client size */
|
|
rclTemp.xLeft = pswpTemp->x;
|
|
rclTemp.xRight = pswpTemp->x + pswpTemp->cx;
|
|
rclTemp.yBottom = pswpTemp->y;
|
|
rclTemp.yTop = pswpTemp->y + pswpTemp->cy;
|
|
WinCalcFrameRect(hwnd, &rclTemp, TRUE);
|
|
|
|
ncx = cx = rclTemp.xRight - rclTemp.xLeft;
|
|
ncy = cy = rclTemp.yTop - rclTemp.yBottom;
|
|
|
|
/* Calculate new size to keep it proportional */
|
|
|
|
if ((pVideo->hidden->ulResizingFlag & TF_LEFT) || (pVideo->hidden->ulResizingFlag & TF_RIGHT))
|
|
{
|
|
/* The window is resized horizontally */
|
|
ncy = pVideo->hidden->SrcBufferDesc.uiYResolution * cx / pVideo->hidden->SrcBufferDesc.uiXResolution;
|
|
} else
|
|
if ((pVideo->hidden->ulResizingFlag & TF_TOP) || (pVideo->hidden->ulResizingFlag & TF_BOTTOM))
|
|
{
|
|
/* The window is resized vertically */
|
|
ncx = pVideo->hidden->SrcBufferDesc.uiXResolution * cy / pVideo->hidden->SrcBufferDesc.uiYResolution;
|
|
}
|
|
|
|
/* Calculate back frame coordinates */
|
|
rclTemp.xLeft = pswpTemp->x;
|
|
rclTemp.xRight = pswpTemp->x + ncx;
|
|
rclTemp.yBottom = pswpTemp->y;
|
|
rclTemp.yTop = pswpTemp->y + ncy;
|
|
WinCalcFrameRect(hwnd, &rclTemp, FALSE);
|
|
|
|
/* Store new size/position info */
|
|
pswpTemp->cx = rclTemp.xRight - rclTemp.xLeft;
|
|
|
|
if (!(pVideo->hidden->ulResizingFlag & TF_TOP))
|
|
{
|
|
pswpTemp->y = pswpTemp->y + pswpTemp->cy - (rclTemp.yTop - rclTemp.yBottom);
|
|
pswpTemp->cy = rclTemp.yTop - rclTemp.yBottom;
|
|
} else
|
|
{
|
|
pswpTemp->cy = rclTemp.yTop - rclTemp.yBottom;
|
|
}
|
|
}
|
|
}
|
|
|
|
result = (*pOldFrameProc)(hwnd, msg, mp1, mp2);
|
|
|
|
if ((pVideo->hidden->bProportionalResize) && (msg==WM_QUERYTRACKINFO))
|
|
{
|
|
ti = (PTRACKINFO) mp2;
|
|
|
|
/* Store the direction of resizing */
|
|
if ((ti->fs & TF_LEFT) || (ti->fs & TF_RIGHT) ||
|
|
(ti->fs & TF_TOP) || (ti->fs & TF_BOTTOM))
|
|
pVideo->hidden->ulResizingFlag = ti->fs;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////
|
|
//
|
|
// 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);
|
|
|
|
// Subclass frame procedure and store old window proc address
|
|
pVideo->hidden->pfnOldFrameProc =
|
|
WinSubclassWindow(pVideo->hidden->hwndFrame, FrameWndProc);
|
|
WinSetWindowULong(pVideo->hidden->hwndFrame, QWL_USER, (ULONG) pVideo);
|
|
|
|
#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);
|
|
SDL_free(cursor->pchData);
|
|
SDL_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 *) SDL_malloc(sizeof(WMcursor));
|
|
if (!pResult) return (WMcursor *) NULL;
|
|
|
|
pchTemp = (char *) SDL_malloc((maxx + 7)/8 * maxy*2);
|
|
if (!pchTemp)
|
|
{
|
|
SDL_free(pResult);
|
|
return (WMcursor *) NULL;
|
|
}
|
|
|
|
SDL_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;
|
|
|
|
SDL_memset(&bmih, 0, sizeof(BITMAPINFOHEADER));
|
|
bmih.cbFix = sizeof(BITMAPINFOHEADER);
|
|
bmih.cx = maxx;
|
|
bmih.cy = 2*maxy;
|
|
bmih.cPlanes = 1;
|
|
bmih.cBitCount = 1;
|
|
|
|
run = (w+7)/8;
|
|
pad = (maxx+7)/8 - run;
|
|
|
|
for (i=0; i<h; i++)
|
|
{
|
|
xptr = pchTemp + (maxx+7)/8 * (maxy-1-i);
|
|
aptr = pchTemp + (maxx+7)/8 * (maxy+maxy-1-i);
|
|
memxor(xptr, data, mask, run);
|
|
xptr += run;
|
|
data += run;
|
|
memnot(aptr, mask, run);
|
|
mask += run;
|
|
aptr += run;
|
|
SDL_memset(xptr, 0, pad);
|
|
xptr += pad;
|
|
SDL_memset(aptr, ~0, pad);
|
|
aptr += pad;
|
|
}
|
|
pad += run;
|
|
for (i=h ; i<maxy; i++ )
|
|
{
|
|
xptr = pchTemp + (maxx+7)/8 * (maxy-1-i);
|
|
aptr = pchTemp + (maxx+7)/8 * (maxy+maxy-1-i);
|
|
|
|
SDL_memset(xptr, 0, (maxx+7)/8);
|
|
xptr += (maxx+7)/8;
|
|
SDL_memset(aptr, ~0, (maxx+7)/8);
|
|
aptr += (maxx+7)/8;
|
|
}
|
|
|
|
hbm = GpiCreateBitmap(hps, (PBITMAPINFOHEADER2)&bmih, CBM_INIT, (PBYTE) pchTemp, (PBITMAPINFO2)&bmi);
|
|
hptr = WinCreatePointer(HWND_DESKTOP, hbm, TRUE, hot_x, maxy - hot_y - 1);
|
|
|
|
#ifdef DEBUG_BUILD
|
|
printf("HotSpot : %d ; %d\n", hot_x, hot_y);
|
|
printf("HPS returned : %x\n", (ULONG)hps);
|
|
printf("HBITMAP returned : %x\n", (ULONG)hbm);
|
|
printf("HPOINTER returned: %x\n", (ULONG)hptr);
|
|
#endif
|
|
|
|
WinReleasePS(hps);
|
|
|
|
#ifdef DEBUG_BUILD
|
|
printf("[CreateWMCursor] : ptr = %p\n", hptr); fflush(stdout);
|
|
#endif
|
|
|
|
pResult->hptr = hptr;
|
|
pResult->hbm = hbm;
|
|
pResult->pchData = pchTemp;
|
|
|
|
#ifdef DEBUG_BUILD
|
|
printf("[CreateWMCursor] : ptr = %p return.\n", hptr); fflush(stdout);
|
|
#endif
|
|
|
|
return (WMcursor *) pResult;
|
|
}
|
|
|
|
WMcursor *os2fslib_CreateWMCursor_FS(_THIS, Uint8 *data, Uint8 *mask,
|
|
int w, int h, int hot_x, int hot_y)
|
|
{
|
|
#ifdef DEBUG_BUILD
|
|
printf("[CreateWMCursor_FS] : returning pointer NULL\n"); fflush(stdout);
|
|
#endif
|
|
|
|
// In FS mode we'll use software cursor
|
|
return (WMcursor *) NULL;
|
|
}
|
|
|
|
/* Show the specified cursor, or hide if cursor is NULL */
|
|
int os2fslib_ShowWMCursor(_THIS, WMcursor *cursor)
|
|
{
|
|
#ifdef DEBUG_BUILD
|
|
printf("[ShowWMCursor] : ptr = %p\n", cursor); fflush(stdout);
|
|
#endif
|
|
|
|
if (cursor)
|
|
{
|
|
WinSetPointer(HWND_DESKTOP, cursor->hptr);
|
|
hptrGlobalPointer = cursor->hptr;
|
|
_this->hidden->iMouseVisible = 1;
|
|
}
|
|
else
|
|
{
|
|
WinSetPointer(HWND_DESKTOP, FALSE);
|
|
hptrGlobalPointer = NULL;
|
|
_this->hidden->iMouseVisible = 0;
|
|
}
|
|
|
|
#ifdef DEBUG_BUILD
|
|
printf("[ShowWMCursor] : ptr = %p, DONE\n", cursor); fflush(stdout);
|
|
#endif
|
|
|
|
return 1;
|
|
}
|
|
|
|
/* Warp the window manager cursor to (x,y)
|
|
If NULL, a mouse motion event is posted internally.
|
|
*/
|
|
void os2fslib_WarpWMCursor(_THIS, Uint16 x, Uint16 y)
|
|
{
|
|
LONG lx, ly;
|
|
SWP swpClient;
|
|
POINTL ptlPoints;
|
|
WinQueryWindowPos(_this->hidden->hwndClient, &swpClient);
|
|
ptlPoints.x = swpClient.x;
|
|
ptlPoints.y = swpClient.y;
|
|
WinMapWindowPoints(_this->hidden->hwndFrame, HWND_DESKTOP, &ptlPoints, 1);
|
|
lx = ptlPoints.x + (x*swpClient.cx) / _this->hidden->SrcBufferDesc.uiXResolution;
|
|
ly = ptlPoints.y + swpClient.cy - ((y*swpClient.cy) / _this->hidden->SrcBufferDesc.uiYResolution) - 1;
|
|
|
|
SDL_PrivateMouseMotion(0, // Buttons not changed
|
|
0, // Absolute position
|
|
x,
|
|
y);
|
|
|
|
WinSetPointerPos(HWND_DESKTOP, lx, ly);
|
|
|
|
}
|
|
|
|
/* If not NULL, this is called when a mouse motion event occurs */
|
|
void os2fslib_MoveWMCursor(_THIS, int x, int y)
|
|
{
|
|
/*
|
|
SDL_Rect rect;
|
|
|
|
#ifdef DEBUG_BUILD
|
|
printf("[MoveWMCursor] : at %d ; %d\n", x, y); fflush(stdout);
|
|
#endif
|
|
|
|
rect.x = x;
|
|
rect.y = y;
|
|
rect.w = 32;
|
|
rect.h = 32;
|
|
os2fslib_UpdateRects(_this, 1, &rect);
|
|
// TODO!
|
|
*/
|
|
}
|
|
|
|
/* Determine whether the mouse should be in relative mode or not.
|
|
This function is called when the input grab state or cursor
|
|
visibility state changes.
|
|
If the cursor is not visible, and the input is grabbed, the
|
|
driver can place the mouse in relative mode, which may result
|
|
in higher accuracy sampling of the pointer motion.
|
|
*/
|
|
void os2fslib_CheckMouseMode(_THIS)
|
|
{
|
|
}
|
|
|
|
static void os2fslib_PumpEvents(_THIS)
|
|
{
|
|
// Notify SDL that if window has been resized!
|
|
if (
|
|
(_this->hidden->pSDLSurface) &&
|
|
(_this->hidden->pSDLSurface->flags & SDL_RESIZABLE) &&
|
|
(
|
|
(_this->hidden->SrcBufferDesc.uiXResolution!=iWindowSizeX) ||
|
|
(_this->hidden->SrcBufferDesc.uiYResolution!=iWindowSizeY)
|
|
) &&
|
|
(iWindowSizeX>0) &&
|
|
(iWindowSizeY>0)
|
|
)
|
|
{
|
|
static time_t prev_time;
|
|
time_t curr_time;
|
|
|
|
curr_time = time(NULL);
|
|
if ((difftime(curr_time, prev_time)>=0.25) ||
|
|
(bWindowResized))
|
|
{
|
|
// Make sure we won't flood the event queue with resize events,
|
|
// only send them at 250 msecs!
|
|
// (or when the window is resized)
|
|
#ifdef DEBUG_BUILD
|
|
printf("[os2fslib_PumpEvents] : Calling PrivateResize (%d %d).\n",
|
|
iWindowSizeX, iWindowSizeY);
|
|
fflush(stdout);
|
|
#endif
|
|
// Tell SDL the new size
|
|
SDL_PrivateResize(iWindowSizeX, iWindowSizeY);
|
|
prev_time = curr_time;
|
|
bWindowResized = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* We don't actually allow hardware surfaces other than the main one */
|
|
static int os2fslib_AllocHWSurface(_THIS, SDL_Surface *surface)
|
|
{
|
|
return(-1);
|
|
}
|
|
static void os2fslib_FreeHWSurface(_THIS, SDL_Surface *surface)
|
|
{
|
|
return;
|
|
}
|
|
|
|
/* We need to wait for vertical retrace on page flipped displays */
|
|
static int os2fslib_LockHWSurface(_THIS, SDL_Surface *surface)
|
|
{
|
|
return(0);
|
|
}
|
|
|
|
static void os2fslib_UnlockHWSurface(_THIS, SDL_Surface *surface)
|
|
{
|
|
return;
|
|
}
|
|
|
|
static int os2fslib_SetColors(_THIS, int firstcolor, int ncolors, SDL_Color *colors)
|
|
{
|
|
printf("[os2fslib_SetColors] : TODO!\n"); fflush(stdout);
|
|
// TODO: Implement paletted modes
|
|
return(1);
|
|
}
|
|
|
|
static void os2fslib_DestroyIcon(HWND hwndFrame)
|
|
{
|
|
if (hptrCurrentIcon)
|
|
{
|
|
WinDestroyPointer(hptrCurrentIcon);
|
|
hptrCurrentIcon = NULL;
|
|
|
|
WinSendMsg(hwndFrame,
|
|
WM_SETICON,
|
|
NULL,
|
|
NULL);
|
|
}
|
|
|
|
}
|
|
|
|
/* Set the window icon image */
|
|
void os2fslib_SetIcon(_THIS, SDL_Surface *icon, Uint8 *mask)
|
|
{
|
|
HWND hwndFrame;
|
|
SDL_Surface *icon_rgb;
|
|
HPOINTER hptrIcon;
|
|
HBITMAP hbm;
|
|
BITMAPINFOHEADER bmih;
|
|
BMPINFO bmi;
|
|
HPS hps;
|
|
char *pchTemp;
|
|
char *pptr, *mptr, *dptr, *dmptr;
|
|
int maxx, maxy, w, h, x, y;
|
|
SDL_Rect bounds;
|
|
|
|
#ifdef DEBUG_BUILD
|
|
printf("[os2fslib_SetIcon] : Creating and setting new icon\n"); fflush(stdout);
|
|
#endif
|
|
|
|
hwndFrame = WinQueryWindow(_this->hidden->hwndClient, QW_PARENT);
|
|
|
|
// Make sure the old icon resource will be free'd!
|
|
os2fslib_DestroyIcon(hwndFrame);
|
|
|
|
if ((!icon) || (!mask))
|
|
return;
|
|
|
|
w = icon->w;
|
|
h = icon->h;
|
|
|
|
maxx = WinQuerySysValue(HWND_DESKTOP, SV_CXICON);
|
|
maxy = WinQuerySysValue(HWND_DESKTOP, SV_CYICON);
|
|
|
|
// Check for max size!
|
|
if ((w>maxx) || (h>maxy))
|
|
return;
|
|
|
|
pchTemp = (char *) SDL_malloc(w * h*2 * 4);
|
|
if (!pchTemp)
|
|
return;
|
|
|
|
SDL_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 )
|
|
{
|
|
SDL_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);
|
|
SDL_free(pchTemp);
|
|
return;
|
|
}
|
|
|
|
/* Copy pixels upside-down from RGB surface into BMP, masked with the icon mask */
|
|
|
|
// Pixels
|
|
pptr = (char *) (icon_rgb->pixels);
|
|
// Mask
|
|
mptr = mask;
|
|
|
|
for (y=0; y<h; y++)
|
|
{
|
|
unsigned char uchMaskByte;
|
|
|
|
// Destination
|
|
dptr = pchTemp + w*4 * (h-y-1);
|
|
// Destination mask
|
|
dmptr = pchTemp + w*h*4 + w*4 * (h-y-1);
|
|
|
|
for (x=0; x<w; x++)
|
|
{
|
|
if (x%8==0)
|
|
{
|
|
uchMaskByte = (unsigned char) (*mptr);
|
|
mptr++;
|
|
} else
|
|
uchMaskByte <<= 1;
|
|
|
|
if (uchMaskByte & 0x80)
|
|
{
|
|
// Copy RGB
|
|
*dptr++ = *pptr++;
|
|
*dptr++ = *pptr++;
|
|
*dptr++ = *pptr++;
|
|
*dptr++ = *pptr++;
|
|
|
|
*dmptr++ = 0;
|
|
*dmptr++ = 0;
|
|
*dmptr++ = 0;
|
|
*dmptr++ = 0;
|
|
} else
|
|
{
|
|
// Set pixels to fully transparent
|
|
*dptr++ = 0; pptr++;
|
|
*dptr++ = 0; pptr++;
|
|
*dptr++ = 0; pptr++;
|
|
*dptr++ = 0; pptr++;
|
|
|
|
*dmptr++ = 255;
|
|
*dmptr++ = 255;
|
|
*dmptr++ = 255;
|
|
*dmptr++ = 255;
|
|
}
|
|
}
|
|
}
|
|
|
|
// There is no more need for the RGB surface
|
|
SDL_FreeSurface(icon_rgb);
|
|
|
|
hps = WinGetPS(_this->hidden->hwndClient);
|
|
|
|
bmi.cbFix = sizeof(BITMAPINFOHEADER);
|
|
bmi.cx = w;
|
|
bmi.cy = 2*h;
|
|
bmi.cPlanes = 1;
|
|
bmi.cBitCount = 32;
|
|
|
|
SDL_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
|
|
SDL_free(pchTemp);
|
|
|
|
// Change icon in frame window
|
|
WinSendMsg(hwndFrame,
|
|
WM_SETICON,
|
|
(MPARAM) hptrIcon,
|
|
NULL);
|
|
|
|
/*
|
|
// Change icon in switchlist
|
|
// Seems like it's not needed, the WM_SETICON already does it.
|
|
{
|
|
PID pidFrame;
|
|
HSWITCH hswitchFrame;
|
|
SWCNTRL swctl;
|
|
|
|
WinQueryWindowProcess(hwndFrame, &pidFrame, NULL);
|
|
hswitchFrame = WinQuerySwitchHandle(hwndFrame, pidFrame);
|
|
WinQuerySwitchEntry(hswitchFrame, &swctl);
|
|
|
|
swctl.hwndIcon = hptrIcon;
|
|
|
|
WinChangeSwitchEntry(hswitchFrame, &swctl);
|
|
}
|
|
*/
|
|
|
|
// Store icon handle in global variable
|
|
hptrCurrentIcon = hptrIcon;
|
|
}
|
|
|
|
// ------------------------ REAL FUNCTIONS -----------------
|
|
|
|
|
|
static void os2fslib_SetCursorManagementFunctions(_THIS, int iForWindowedMode)
|
|
{
|
|
if (iForWindowedMode)
|
|
{
|
|
_this->FreeWMCursor = os2fslib_FreeWMCursor;
|
|
_this->CreateWMCursor = os2fslib_CreateWMCursor_Win;
|
|
_this->ShowWMCursor = os2fslib_ShowWMCursor;
|
|
_this->WarpWMCursor = os2fslib_WarpWMCursor;
|
|
_this->MoveWMCursor = os2fslib_MoveWMCursor;
|
|
_this->CheckMouseMode = NULL;//os2fslib_CheckMouseMode;
|
|
} else
|
|
{
|
|
// We'll have software mouse cursor in FS mode!
|
|
_this->FreeWMCursor = os2fslib_FreeWMCursor;
|
|
_this->CreateWMCursor = os2fslib_CreateWMCursor_FS;
|
|
_this->ShowWMCursor = os2fslib_ShowWMCursor;
|
|
_this->WarpWMCursor = os2fslib_WarpWMCursor;
|
|
_this->MoveWMCursor = os2fslib_MoveWMCursor;
|
|
_this->CheckMouseMode = NULL;//os2fslib_CheckMouseMode;
|
|
}
|
|
}
|
|
|
|
static void os2fslib_InitOSKeymap(_THIS)
|
|
{
|
|
int i;
|
|
|
|
iShiftIsPressed = 0;
|
|
|
|
/* Map the VK and CH keysyms */
|
|
for ( i=0; i<=255; ++i )
|
|
HWScanKeyMap[i] = SDLK_UNKNOWN;
|
|
|
|
// First line of keyboard:
|
|
HWScanKeyMap[0x1] = SDLK_ESCAPE;
|
|
HWScanKeyMap[0x3b] = SDLK_F1;
|
|
HWScanKeyMap[0x3c] = SDLK_F2;
|
|
HWScanKeyMap[0x3d] = SDLK_F3;
|
|
HWScanKeyMap[0x3e] = SDLK_F4;
|
|
HWScanKeyMap[0x3f] = SDLK_F5;
|
|
HWScanKeyMap[0x40] = SDLK_F6;
|
|
HWScanKeyMap[0x41] = SDLK_F7;
|
|
HWScanKeyMap[0x42] = SDLK_F8;
|
|
HWScanKeyMap[0x43] = SDLK_F9;
|
|
HWScanKeyMap[0x44] = SDLK_F10;
|
|
HWScanKeyMap[0x57] = SDLK_F11;
|
|
HWScanKeyMap[0x58] = SDLK_F12;
|
|
HWScanKeyMap[0x5d] = SDLK_PRINT;
|
|
HWScanKeyMap[0x46] = SDLK_SCROLLOCK;
|
|
HWScanKeyMap[0x5f] = SDLK_PAUSE;
|
|
|
|
// Second line of keyboard:
|
|
HWScanKeyMap[0x29] = SDLK_BACKQUOTE;
|
|
HWScanKeyMap[0x2] = SDLK_1;
|
|
HWScanKeyMap[0x3] = SDLK_2;
|
|
HWScanKeyMap[0x4] = SDLK_3;
|
|
HWScanKeyMap[0x5] = SDLK_4;
|
|
HWScanKeyMap[0x6] = SDLK_5;
|
|
HWScanKeyMap[0x7] = SDLK_6;
|
|
HWScanKeyMap[0x8] = SDLK_7;
|
|
HWScanKeyMap[0x9] = SDLK_8;
|
|
HWScanKeyMap[0xa] = SDLK_9;
|
|
HWScanKeyMap[0xb] = SDLK_0;
|
|
HWScanKeyMap[0xc] = SDLK_MINUS;
|
|
HWScanKeyMap[0xd] = SDLK_EQUALS;
|
|
HWScanKeyMap[0xe] = SDLK_BACKSPACE;
|
|
HWScanKeyMap[0x68] = SDLK_INSERT;
|
|
HWScanKeyMap[0x60] = SDLK_HOME;
|
|
HWScanKeyMap[0x62] = SDLK_PAGEUP;
|
|
HWScanKeyMap[0x45] = SDLK_NUMLOCK;
|
|
HWScanKeyMap[0x5c] = SDLK_KP_DIVIDE;
|
|
HWScanKeyMap[0x37] = SDLK_KP_MULTIPLY;
|
|
HWScanKeyMap[0x4a] = SDLK_KP_MINUS;
|
|
|
|
// Third line of keyboard:
|
|
HWScanKeyMap[0xf] = SDLK_TAB;
|
|
HWScanKeyMap[0x10] = SDLK_q;
|
|
HWScanKeyMap[0x11] = SDLK_w;
|
|
HWScanKeyMap[0x12] = SDLK_e;
|
|
HWScanKeyMap[0x13] = SDLK_r;
|
|
HWScanKeyMap[0x14] = SDLK_t;
|
|
HWScanKeyMap[0x15] = SDLK_y;
|
|
HWScanKeyMap[0x16] = SDLK_u;
|
|
HWScanKeyMap[0x17] = SDLK_i;
|
|
HWScanKeyMap[0x18] = SDLK_o;
|
|
HWScanKeyMap[0x19] = SDLK_p;
|
|
HWScanKeyMap[0x1a] = SDLK_LEFTBRACKET;
|
|
HWScanKeyMap[0x1b] = SDLK_RIGHTBRACKET;
|
|
HWScanKeyMap[0x1c] = SDLK_RETURN;
|
|
HWScanKeyMap[0x69] = SDLK_DELETE;
|
|
HWScanKeyMap[0x65] = SDLK_END;
|
|
HWScanKeyMap[0x67] = SDLK_PAGEDOWN;
|
|
HWScanKeyMap[0x47] = SDLK_KP7;
|
|
HWScanKeyMap[0x48] = SDLK_KP8;
|
|
HWScanKeyMap[0x49] = SDLK_KP9;
|
|
HWScanKeyMap[0x4e] = SDLK_KP_PLUS;
|
|
|
|
// Fourth line of keyboard:
|
|
HWScanKeyMap[0x3a] = SDLK_CAPSLOCK;
|
|
HWScanKeyMap[0x1e] = SDLK_a;
|
|
HWScanKeyMap[0x1f] = SDLK_s;
|
|
HWScanKeyMap[0x20] = SDLK_d;
|
|
HWScanKeyMap[0x21] = SDLK_f;
|
|
HWScanKeyMap[0x22] = SDLK_g;
|
|
HWScanKeyMap[0x23] = SDLK_h;
|
|
HWScanKeyMap[0x24] = SDLK_j;
|
|
HWScanKeyMap[0x25] = SDLK_k;
|
|
HWScanKeyMap[0x26] = SDLK_l;
|
|
HWScanKeyMap[0x27] = SDLK_SEMICOLON;
|
|
HWScanKeyMap[0x28] = SDLK_QUOTE;
|
|
HWScanKeyMap[0x2b] = SDLK_BACKSLASH;
|
|
HWScanKeyMap[0x4b] = SDLK_KP4;
|
|
HWScanKeyMap[0x4c] = SDLK_KP5;
|
|
HWScanKeyMap[0x4d] = SDLK_KP6;
|
|
|
|
// Fifth line of keyboard:
|
|
HWScanKeyMap[0x2a] = SDLK_LSHIFT;
|
|
HWScanKeyMap[0x56] = SDLK_WORLD_1; // Code 161, letter i' on hungarian keyboard
|
|
HWScanKeyMap[0x2c] = SDLK_z;
|
|
HWScanKeyMap[0x2d] = SDLK_x;
|
|
HWScanKeyMap[0x2e] = SDLK_c;
|
|
HWScanKeyMap[0x2f] = SDLK_v;
|
|
HWScanKeyMap[0x30] = SDLK_b;
|
|
HWScanKeyMap[0x31] = SDLK_n;
|
|
HWScanKeyMap[0x32] = SDLK_m;
|
|
HWScanKeyMap[0x33] = SDLK_COMMA;
|
|
HWScanKeyMap[0x34] = SDLK_PERIOD;
|
|
HWScanKeyMap[0x35] = SDLK_SLASH;
|
|
HWScanKeyMap[0x36] = SDLK_RSHIFT;
|
|
HWScanKeyMap[0x61] = SDLK_UP;
|
|
HWScanKeyMap[0x4f] = SDLK_KP1;
|
|
HWScanKeyMap[0x50] = SDLK_KP2;
|
|
HWScanKeyMap[0x51] = SDLK_KP3;
|
|
HWScanKeyMap[0x5a] = SDLK_KP_ENTER;
|
|
|
|
// Sixth line of keyboard:
|
|
HWScanKeyMap[0x1d] = SDLK_LCTRL;
|
|
HWScanKeyMap[0x7e] = SDLK_LSUPER; // Windows key
|
|
HWScanKeyMap[0x38] = SDLK_LALT;
|
|
HWScanKeyMap[0x39] = SDLK_SPACE;
|
|
HWScanKeyMap[0x5e] = SDLK_RALT;// Actually, altgr on my keyboard...
|
|
HWScanKeyMap[0x7f] = SDLK_RSUPER;
|
|
HWScanKeyMap[0x7c] = SDLK_MENU;
|
|
HWScanKeyMap[0x5b] = SDLK_RCTRL;
|
|
HWScanKeyMap[0x63] = SDLK_LEFT;
|
|
HWScanKeyMap[0x66] = SDLK_DOWN;
|
|
HWScanKeyMap[0x64] = SDLK_RIGHT;
|
|
HWScanKeyMap[0x52] = SDLK_KP0;
|
|
HWScanKeyMap[0x53] = SDLK_KP_PERIOD;
|
|
}
|
|
|
|
|
|
/* Iconify the window.
|
|
This function returns 1 if there is a window manager and the
|
|
window was actually iconified, it returns 0 otherwise.
|
|
*/
|
|
int os2fslib_IconifyWindow(_THIS)
|
|
{
|
|
HAB hab;
|
|
HMQ hmq;
|
|
ERRORID hmqerror;
|
|
|
|
// If there is no more window, nothing we can do!
|
|
if (_this->hidden->iPMThreadStatus!=1) return 0;
|
|
|
|
// Cannot do anything in fullscreen mode!
|
|
if (FSLib_QueryFSMode(_this->hidden->hwndClient))
|
|
return 0;
|
|
|
|
// Make sure this thread is prepared for using the Presentation Manager!
|
|
hab = WinInitialize(0);
|
|
hmq = WinCreateMsgQueue(hab,0);
|
|
// Remember if there was an error at WinCreateMsgQueue(), because we don't
|
|
// want to destroy somebody else's queue later. :)
|
|
hmqerror = WinGetLastError(hab);
|
|
|
|
WinSetWindowPos(_this->hidden->hwndFrame, HWND_TOP,
|
|
0, 0, 0, 0, SWP_MINIMIZE);
|
|
|
|
// Now destroy the message queue, if we've created it!
|
|
if (ERRORIDERROR(hmqerror)==0)
|
|
WinDestroyMsgQueue(hmq);
|
|
|
|
return 1;
|
|
}
|
|
|
|
static SDL_GrabMode os2fslib_GrabInput(_THIS, SDL_GrabMode mode)
|
|
{
|
|
HAB hab;
|
|
HMQ hmq;
|
|
ERRORID hmqerror;
|
|
|
|
|
|
// If there is no more window, nothing we can do!
|
|
if (_this->hidden->iPMThreadStatus!=1)
|
|
return SDL_GRAB_OFF;
|
|
|
|
// Make sure this thread is prepared for using the Presentation Manager!
|
|
hab = WinInitialize(0);
|
|
hmq = WinCreateMsgQueue(hab,0);
|
|
// Remember if there was an error at WinCreateMsgQueue(), because we don't
|
|
// want to destroy somebody else's queue later. :)
|
|
hmqerror = WinGetLastError(hab);
|
|
|
|
|
|
if (mode == SDL_GRAB_OFF)
|
|
{
|
|
#ifdef DEBUG_BUILD
|
|
printf("[os2fslib_GrabInput] : Releasing mouse\n"); fflush(stdout);
|
|
#endif
|
|
|
|
// Release the mouse
|
|
bMouseCapturable = 0;
|
|
if (bMouseCaptured)
|
|
{
|
|
WinSetCapture(HWND_DESKTOP, NULLHANDLE);
|
|
bMouseCaptured = 0;
|
|
}
|
|
} else
|
|
{
|
|
#ifdef DEBUG_BUILD
|
|
printf("[os2fslib_GrabInput] : Capturing mouse\n"); fflush(stdout);
|
|
#endif
|
|
|
|
// Capture the mouse
|
|
bMouseCapturable = 1;
|
|
if (WinQueryFocus(HWND_DESKTOP) == _this->hidden->hwndClient)
|
|
{
|
|
WinSetCapture(HWND_DESKTOP, _this->hidden->hwndClient);
|
|
bMouseCaptured = 1;
|
|
{
|
|
SWP swpClient;
|
|
POINTL ptl;
|
|
// Center the mouse to the middle of the window!
|
|
WinQueryWindowPos(_this->hidden->hwndClient, &swpClient);
|
|
ptl.x = 0; ptl.y = 0;
|
|
WinMapWindowPoints(_this->hidden->hwndClient, HWND_DESKTOP, &ptl, 1);
|
|
_this->hidden->iSkipWMMOUSEMOVE++; /* Don't take next WM_MOUSEMOVE into account! */
|
|
WinSetPointerPos(HWND_DESKTOP,
|
|
ptl.x + swpClient.cx/2,
|
|
ptl.y + swpClient.cy/2);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Now destroy the message queue, if we've created it!
|
|
if (ERRORIDERROR(hmqerror)==0)
|
|
WinDestroyMsgQueue(hmq);
|
|
|
|
return mode;
|
|
}
|
|
|
|
/* Set the title and icon text */
|
|
static void os2fslib_SetCaption(_THIS, const char *title, const char *icon)
|
|
{
|
|
HAB hab;
|
|
HMQ hmq;
|
|
ERRORID hmqerror;
|
|
|
|
// If there is no more window, nothing we can do!
|
|
if (_this->hidden->iPMThreadStatus!=1) return;
|
|
|
|
// Make sure this thread is prepared for using the Presentation Manager!
|
|
hab = WinInitialize(0);
|
|
hmq = WinCreateMsgQueue(hab,0);
|
|
// Remember if there was an error at WinCreateMsgQueue(), because we don't
|
|
// want to destroy somebody else's queue later. :)
|
|
hmqerror = WinGetLastError(hab);
|
|
|
|
WinSetWindowText(_this->hidden->hwndFrame, (char *) title);
|
|
|
|
// Now destroy the message queue, if we've created it!
|
|
if (ERRORIDERROR(hmqerror)==0)
|
|
WinDestroyMsgQueue(hmq);
|
|
}
|
|
|
|
static int os2fslib_ToggleFullScreen(_THIS, int on)
|
|
{
|
|
#ifdef DEBUG_BUILD
|
|
printf("[os2fslib_ToggleFullScreen] : %d\n", on); fflush(stdout);
|
|
#endif
|
|
// If there is no more window, nothing we can do!
|
|
if (_this->hidden->iPMThreadStatus!=1) return 0;
|
|
|
|
FSLib_ToggleFSMode(_this->hidden->hwndClient, on);
|
|
/* Cursor manager functions to Windowed/FS mode*/
|
|
os2fslib_SetCursorManagementFunctions(_this, !on);
|
|
return 1;
|
|
}
|
|
|
|
/* This is called after the video mode has been set, to get the
|
|
initial mouse state. It should queue events as necessary to
|
|
properly represent the current mouse focus and position.
|
|
*/
|
|
static void os2fslib_UpdateMouse(_THIS)
|
|
{
|
|
POINTL ptl;
|
|
HAB hab;
|
|
HMQ hmq;
|
|
ERRORID hmqerror;
|
|
SWP swpClient;
|
|
|
|
// If there is no more window, nothing we can do!
|
|
if (_this->hidden->iPMThreadStatus!=1) return;
|
|
|
|
|
|
// Make sure this thread is prepared for using the Presentation Manager!
|
|
hab = WinInitialize(0);
|
|
hmq = WinCreateMsgQueue(hab,0);
|
|
// Remember if there was an error at WinCreateMsgQueue(), because we don't
|
|
// want to destroy somebody else's queue later. :)
|
|
hmqerror = WinGetLastError(hab);
|
|
|
|
|
|
|
|
if (_this->hidden->fInFocus)
|
|
{
|
|
// If our app is in focus
|
|
SDL_PrivateAppActive(1, SDL_APPMOUSEFOCUS);
|
|
SDL_PrivateAppActive(1, SDL_APPINPUTFOCUS);
|
|
SDL_PrivateAppActive(1, SDL_APPACTIVE);
|
|
WinQueryPointerPos(HWND_DESKTOP, &ptl);
|
|
WinMapWindowPoints(HWND_DESKTOP, _this->hidden->hwndClient, &ptl, 1);
|
|
WinQueryWindowPos(_this->hidden->hwndClient, &swpClient);
|
|
// Convert OS/2 mouse position to SDL position, and also scale it!
|
|
ptl.x = ptl.x * _this->hidden->SrcBufferDesc.uiXResolution / swpClient.cx;
|
|
ptl.y = ptl.y * _this->hidden->SrcBufferDesc.uiYResolution / swpClient.cy;
|
|
ptl.y = _this->hidden->SrcBufferDesc.uiYResolution - ptl.y - 1;
|
|
SDL_PrivateMouseMotion(0, 0, (Sint16) (ptl.x), (Sint16) (ptl.y));
|
|
} else
|
|
{
|
|
// If we're not in focus
|
|
SDL_PrivateAppActive(0, SDL_APPMOUSEFOCUS);
|
|
SDL_PrivateAppActive(0, SDL_APPINPUTFOCUS);
|
|
SDL_PrivateAppActive(0, SDL_APPACTIVE);
|
|
SDL_PrivateMouseMotion(0, 0, (Sint16) -1, (Sint16) -1);
|
|
}
|
|
|
|
// Now destroy the message queue, if we've created it!
|
|
if (ERRORIDERROR(hmqerror)==0)
|
|
WinDestroyMsgQueue(hmq);
|
|
|
|
}
|
|
|
|
/* This pointer should exist in the native video subsystem and should
|
|
point to an appropriate update function for the current video mode
|
|
*/
|
|
static void os2fslib_UpdateRects(_THIS, int numrects, SDL_Rect *rects)
|
|
{
|
|
// If there is no more window, nothing we can do!
|
|
if (_this->hidden->iPMThreadStatus!=1) return;
|
|
|
|
#ifdef BITBLT_IN_WINMESSAGEPROC
|
|
WinSendMsg(_this->hidden->hwndClient,
|
|
WM_UPDATERECTSREQUEST,
|
|
(MPARAM) numrects,
|
|
(MPARAM) rects);
|
|
#else
|
|
if (DosRequestMutexSem(_this->hidden->hmtxUseSrcBuffer, SEM_INDEFINITE_WAIT)==NO_ERROR)
|
|
{
|
|
int i;
|
|
|
|
if (_this->hidden->pSDLSurface)
|
|
{
|
|
#ifndef RESIZE_EVEN_IF_RESIZABLE
|
|
SWP swp;
|
|
// But only blit if the window is not resizable, or if
|
|
// the window is resizable and the source buffer size is the
|
|
// same as the destination buffer size!
|
|
WinQueryWindowPos(_this->hidden->hwndClient, &swp);
|
|
if ((_this->hidden->pSDLSurface) &&
|
|
(_this->hidden->pSDLSurface->flags & SDL_RESIZABLE) &&
|
|
((swp.cx != _this->hidden->SrcBufferDesc.uiXResolution) ||
|
|
(swp.cy != _this->hidden->SrcBufferDesc.uiYResolution)
|
|
) &&
|
|
(!FSLib_QueryFSMode(_this->hidden->hwndClient))
|
|
)
|
|
{
|
|
// Resizable surface and in resizing!
|
|
// So, don't blit now!
|
|
#ifdef DEBUG_BUILD
|
|
printf("[UpdateRects] : Skipping blit while resizing!\n"); fflush(stdout);
|
|
#endif
|
|
} else
|
|
#endif
|
|
{
|
|
/*
|
|
// Blit the whole window
|
|
FSLIB_BITBLT(_this->hidden->hwndClient, _this->hidden->pchSrcBuffer,
|
|
0, 0,
|
|
_this->hidden->SrcBufferDesc.uiXResolution,
|
|
_this->hidden->SrcBufferDesc.uiYResolution);
|
|
*/
|
|
#ifdef DEBUG_BUILD
|
|
printf("[os2fslib_UpdateRects] : Blitting!\n"); fflush(stdout);
|
|
#endif
|
|
|
|
// Blit the changed areas
|
|
for (i=0; i<numrects; i++)
|
|
FSLIB_BITBLT(_this->hidden->hwndClient, _this->hidden->pchSrcBuffer,
|
|
rects[i].y, rects[i].x, rects[i].w, rects[i].h);
|
|
}
|
|
}
|
|
#ifdef DEBUG_BUILD
|
|
else
|
|
printf("[os2fslib_UpdateRects] : No public surface!\n"); fflush(stdout);
|
|
#endif
|
|
DosReleaseMutexSem(_this->hidden->hmtxUseSrcBuffer);
|
|
}
|
|
#ifdef DEBUG_BUILD
|
|
else
|
|
printf("[os2fslib_UpdateRects] : Error in mutex!\n"); fflush(stdout);
|
|
#endif
|
|
#endif
|
|
}
|
|
|
|
|
|
/* Reverse the effects VideoInit() -- called if VideoInit() fails
|
|
or if the application is shutting down the video subsystem.
|
|
*/
|
|
static void os2fslib_VideoQuit(_THIS)
|
|
{
|
|
#ifdef DEBUG_BUILD
|
|
printf("[os2fslib_VideoQuit]\n"); fflush(stdout);
|
|
#endif
|
|
// Close PM stuff if running!
|
|
if (_this->hidden->iPMThreadStatus == 1)
|
|
{
|
|
int iTimeout;
|
|
WinPostMsg(_this->hidden->hwndFrame, WM_QUIT, (MPARAM) 0, (MPARAM) 0);
|
|
// HACK: We had this line before:
|
|
//DosWaitThread((TID *) &(_this->hidden->tidPMThread), DCWW_WAIT);
|
|
// We don't use it, because the PMThread will never stop, or if it stops,
|
|
// it will kill the whole process as a emergency fallback.
|
|
// So, we only check for the iPMThreadStatus stuff!
|
|
#ifdef DEBUG_BUILD
|
|
printf("[os2fslib_VideoQuit] : Waiting for PM thread to die\n"); fflush(stdout);
|
|
#endif
|
|
|
|
iTimeout=0;
|
|
while ((_this->hidden->iPMThreadStatus == 1) && (iTimeout<100))
|
|
{
|
|
iTimeout++;
|
|
DosSleep(64);
|
|
}
|
|
|
|
#ifdef DEBUG_BUILD
|
|
printf("[os2fslib_VideoQuit] : End of wait.\n"); fflush(stdout);
|
|
#endif
|
|
|
|
if (_this->hidden->iPMThreadStatus == 1)
|
|
{
|
|
#ifdef DEBUG_BUILD
|
|
printf("[os2fslib_VideoQuit] : Killing PM thread!\n"); fflush(stdout);
|
|
#endif
|
|
|
|
_this->hidden->iPMThreadStatus = 0;
|
|
DosKillThread(_this->hidden->tidPMThread);
|
|
|
|
if (_this->hidden->hwndFrame)
|
|
{
|
|
#ifdef DEBUG_BUILD
|
|
printf("[os2fslib_VideoQuit] : Destroying PM window!\n"); fflush(stdout);
|
|
#endif
|
|
|
|
WinDestroyWindow(_this->hidden->hwndFrame); _this->hidden->hwndFrame=NULL;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
// Free result of an old ListModes() call, because there is
|
|
// no FreeListModes() call in SDL!
|
|
if (_this->hidden->pListModesResult)
|
|
{
|
|
SDL_free(_this->hidden->pListModesResult); _this->hidden->pListModesResult = NULL;
|
|
}
|
|
|
|
// Free list of available fullscreen modes
|
|
if (_this->hidden->pAvailableFSLibVideoModes)
|
|
{
|
|
FSLib_FreeVideoModeList(_this->hidden->pAvailableFSLibVideoModes);
|
|
_this->hidden->pAvailableFSLibVideoModes = NULL;
|
|
}
|
|
|
|
// Free application icon if we had one
|
|
if (hptrCurrentIcon)
|
|
{
|
|
WinDestroyPointer(hptrCurrentIcon);
|
|
hptrCurrentIcon = NULL;
|
|
}
|
|
}
|
|
|
|
/* Set the requested video mode, returning a surface which will be
|
|
set to the SDL_VideoSurface. The width and height will already
|
|
be verified by ListModes(), and the video subsystem is free to
|
|
set the mode to a supported bit depth different from the one
|
|
specified -- the desired bpp will be emulated with a shadow
|
|
surface if necessary. If a new mode is returned, this function
|
|
should take care of cleaning up the current mode.
|
|
*/
|
|
static SDL_Surface *os2fslib_SetVideoMode(_THIS, SDL_Surface *current,
|
|
int width, int height, int bpp, Uint32 flags)
|
|
{
|
|
static int bFirstCall = 1;
|
|
FSLib_VideoMode_p pModeInfo, pModeInfoFound;
|
|
FSLib_VideoMode TempModeInfo;
|
|
HAB hab;
|
|
HMQ hmq;
|
|
ERRORID hmqerror;
|
|
RECTL rectl;
|
|
SDL_Surface *pResult;
|
|
|
|
// If there is no more window, nothing we can do!
|
|
if (_this->hidden->iPMThreadStatus!=1) return NULL;
|
|
|
|
#ifdef DEBUG_BUILD
|
|
printf("[os2fslib_SetVideoMode] : Request for %dx%d @ %dBPP, flags=0x%x\n", width, height, bpp, flags); fflush(stdout);
|
|
#endif
|
|
|
|
// We don't support palette modes!
|
|
if (bpp==8) bpp=32;
|
|
|
|
// Also, we don't support resizable modes in fullscreen mode.
|
|
if (flags & SDL_RESIZABLE)
|
|
flags &= ~SDL_FULLSCREEN;
|
|
|
|
// No double buffered mode
|
|
if (flags & SDL_DOUBLEBUF)
|
|
flags &= ~SDL_DOUBLEBUF;
|
|
|
|
// And, we don't support HWSURFACE yet.
|
|
if (flags & SDL_HWSURFACE)
|
|
{
|
|
flags &= ~SDL_HWSURFACE;
|
|
flags |= SDL_SWSURFACE;
|
|
}
|
|
|
|
#ifdef DEBUG_BUILD
|
|
printf("[os2fslib_SetVideoMode] : Changed request to %dx%d @ %dBPP, flags=0x%x\n", width, height, bpp, flags); fflush(stdout);
|
|
#endif
|
|
|
|
// First check if there is such a video mode they want!
|
|
pModeInfoFound = NULL;
|
|
|
|
// For fullscreen mode we don't support every resolution!
|
|
// So, go through the video modes, and check for such a resolution!
|
|
pModeInfoFound = NULL;
|
|
pModeInfo = _this->hidden->pAvailableFSLibVideoModes;
|
|
|
|
while (pModeInfo)
|
|
{
|
|
// Check all available fullscreen modes for this resolution
|
|
if ((pModeInfo->uiXResolution == width) &&
|
|
(pModeInfo->uiYResolution == height) &&
|
|
(pModeInfo->uiBPP!=8)) // palettized modes not yet supported
|
|
{
|
|
// If good resolution, try to find the exact BPP, or at least
|
|
// something similar...
|
|
if (!pModeInfoFound)
|
|
pModeInfoFound = pModeInfo;
|
|
else
|
|
if ((pModeInfoFound->uiBPP!=bpp) &&
|
|
(pModeInfoFound->uiBPP<pModeInfo->uiBPP))
|
|
pModeInfoFound = pModeInfo;
|
|
}
|
|
pModeInfo = pModeInfo->pNext;
|
|
}
|
|
|
|
// If we did not find a good fullscreen mode, then try a similar
|
|
if (!pModeInfoFound)
|
|
{
|
|
#ifdef DEBUG_BUILD
|
|
printf("[os2fslib_SetVideoMode] : Requested video mode not found, looking for a similar one!\n"); fflush(stdout);
|
|
#endif
|
|
// Go through the video modes again, and find a similar resolution!
|
|
pModeInfo = _this->hidden->pAvailableFSLibVideoModes;
|
|
while (pModeInfo)
|
|
{
|
|
// Check all available fullscreen modes for this resolution
|
|
if ((pModeInfo->uiXResolution >= width) &&
|
|
(pModeInfo->uiYResolution >= height) &&
|
|
(pModeInfo->uiBPP == bpp))
|
|
{
|
|
if (!pModeInfoFound)
|
|
pModeInfoFound = pModeInfo;
|
|
else
|
|
if (((pModeInfoFound->uiXResolution-width)*(pModeInfoFound->uiYResolution-height))>
|
|
((pModeInfo->uiXResolution-width)*(pModeInfo->uiYResolution-height)))
|
|
{
|
|
// Found a mode which is closer than the current one
|
|
pModeInfoFound = pModeInfo;
|
|
}
|
|
}
|
|
pModeInfo = pModeInfo->pNext;
|
|
}
|
|
}
|
|
|
|
// If we did not find a good fullscreen mode, then return NULL
|
|
if (!pModeInfoFound)
|
|
{
|
|
#ifdef DEBUG_BUILD
|
|
printf("[os2fslib_SetVideoMode] : Requested video mode not found!\n"); fflush(stdout);
|
|
#endif
|
|
return NULL;
|
|
}
|
|
|
|
#ifdef DEBUG_BUILD
|
|
printf("[os2fslib_SetVideoMode] : Found mode!\n"); fflush(stdout);
|
|
#endif
|
|
|
|
// We'll possibly adjust the structure, so copy out the values
|
|
// into TempModeInfo!
|
|
SDL_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!
|
|
SDL_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)
|
|
{
|
|
SDL_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 *) SDL_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**) SDL_malloc(2*sizeof(SDL_Rect*));
|
|
if (_this->hidden->pListModesResult)
|
|
{
|
|
_this->hidden->pListModesResult[0] = pRect;
|
|
_this->hidden->pListModesResult[1] = NULL;
|
|
} else
|
|
{
|
|
SDL_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**) SDL_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
|
|
{
|
|
SDL_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;
|
|
|
|
if (getenv("SDL_USE_PROPORTIONAL_WINDOW"))
|
|
_this->hidden->bProportionalResize = 1;
|
|
else
|
|
{
|
|
PPIB pib;
|
|
PTIB tib;
|
|
char *pchFileName, *pchTemp;
|
|
char achConfigFile[CCHMAXPATH];
|
|
FILE *hFile;
|
|
|
|
/* No environment variable to have proportional window.
|
|
* Ok, let's check if this executable is in config file!
|
|
*/
|
|
_this->hidden->bProportionalResize = 0;
|
|
|
|
DosGetInfoBlocks(&tib, &pib);
|
|
pchTemp = pchFileName = pib->pib_pchcmd;
|
|
while (*pchTemp)
|
|
{
|
|
if (*pchTemp=='\\')
|
|
pchFileName = pchTemp+1;
|
|
pchTemp++;
|
|
}
|
|
if (getenv("HOME"))
|
|
{
|
|
sprintf(achConfigFile, "%s\\.sdl.proportionals", getenv("HOME"));
|
|
hFile = fopen(achConfigFile, "rt");
|
|
if (!hFile)
|
|
{
|
|
/* Seems like the file cannot be opened or does not exist.
|
|
* Let's try to create it with defaults!
|
|
*/
|
|
hFile = fopen(achConfigFile, "wt");
|
|
if (hFile)
|
|
{
|
|
fprintf(hFile, "; This file is a config file of SDL/2, containing\n");
|
|
fprintf(hFile, "; the list of executables that must have proportional\n");
|
|
fprintf(hFile, "; windows.\n");
|
|
fprintf(hFile, ";\n");
|
|
fprintf(hFile, "; You can add executable filenames into this file,\n");
|
|
fprintf(hFile, "; one under the other. If SDL finds that a given\n");
|
|
fprintf(hFile, "; program is in this list, then that application\n");
|
|
fprintf(hFile, "; will have proportional windows, just like if\n");
|
|
fprintf(hFile, "; the SET SDL_USE_PROPORTIONAL_WINDOW env. variable\n");
|
|
fprintf(hFile, "; would have been set for that process.\n");
|
|
fprintf(hFile, ";\n");
|
|
fprintf(hFile, "\n");
|
|
fprintf(hFile, "dosbox.exe\n");
|
|
fclose(hFile);
|
|
}
|
|
|
|
hFile = fopen(achConfigFile, "rt");
|
|
}
|
|
|
|
if (hFile)
|
|
{
|
|
while (fgets(achConfigFile, sizeof(achConfigFile), hFile))
|
|
{
|
|
/* Cut \n from end of string */
|
|
|
|
while (achConfigFile[strlen(achConfigFile)-1] == '\n')
|
|
achConfigFile[strlen(achConfigFile)-1] = 0;
|
|
|
|
/* Compare... */
|
|
if (stricmp(achConfigFile, pchFileName)==0)
|
|
{
|
|
/* Found it in config file! */
|
|
_this->hidden->bProportionalResize = 1;
|
|
break;
|
|
}
|
|
}
|
|
fclose(hFile);
|
|
}
|
|
}
|
|
}
|
|
|
|
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!
|
|
SDL_memcpy(&(_this->hidden->SrcBufferDesc), _this->hidden->pAvailableFSLibVideoModes, sizeof(_this->hidden->SrcBufferDesc));
|
|
// Allocate new video buffer!
|
|
_this->hidden->pchSrcBuffer = (char *) SDL_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)
|
|
SDL_free(_this->hidden->pListModesResult);
|
|
if (_this->hidden->pchSrcBuffer)
|
|
SDL_free(_this->hidden->pchSrcBuffer);
|
|
DosCloseMutexSem(_this->hidden->hmtxUseSrcBuffer);
|
|
SDL_free(_this->hidden);
|
|
SDL_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 *)SDL_malloc(sizeof(SDL_VideoDevice));
|
|
if ( device )
|
|
{
|
|
SDL_memset(device, 0, (sizeof *device));
|
|
// Also allocate memory for private data
|
|
device->hidden = (struct SDL_PrivateVideoData *) SDL_malloc((sizeof(struct SDL_PrivateVideoData)));
|
|
}
|
|
if ( (device == NULL) || (device->hidden == NULL) )
|
|
{
|
|
SDL_OutOfMemory();
|
|
if ( device )
|
|
SDL_free(device);
|
|
return NULL;
|
|
}
|
|
SDL_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!");
|
|
SDL_free(device->hidden);
|
|
SDL_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
|
|
};
|
|
|