simh-testsetgenerator/display/win32.c
Mark Pizzolato b804964514 PDP11, PDP1, TX-0: Added SDL based graphics support using sim_video.
Both VT11 and VS60 properly autoconfigure on the PDP11.
PDP11 now runs Lunar Lander on all SDL supported platforms.
Reworked refresh logic to not require internal delays in the display library
2016-01-29 10:16:30 -08:00

422 lines
10 KiB
C

/*
* $Id: win32.c,v 1.39 2005/01/14 18:58:03 phil Exp $
* Win32 support for XY display simulator
* Phil Budne <phil@ultimate.com>
* September 2003
* Revised by Douglas A. Gwyn, 05 Feb. 2004
*/
/*
* Copyright (c) 2003-2004, Philip L. Budne
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
* Except as contained in this notice, the names of the authors shall
* not be used in advertising or otherwise to promote the sale, use or
* other dealings in this Software without prior written authorization
* from the authors.
*/
/* use a thread to handle windows messages; */
#define THREADS
/*
* BUGS:
* Does not allow you to close display window;
* would need to tear down both system, and system independent data.
*
* now tries to handle PAINT message, as yet untested!!
*/
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include "ws.h"
#include "xy.h"
#ifndef PIX_SIZE
#define PIX_SIZE 1
#endif
#define APP_CLASS "XYAppClass"
#define APP_MENU "XYAppMenu" /* ?? */
/*
* light pen location
* see ws.h for full description
*/
int ws_lp_x = -1;
int ws_lp_y = -1;
static HWND static_wh;
static HINSTANCE static_inst;
static int xpixels, ypixels;
static char *window_name;
static HBRUSH white_brush;
static HBRUSH black_brush;
#ifdef SWITCH_CURSORS
static HCURSOR cross, arrow;
#endif
static __inline int
map_key(int k)
{
switch (k) {
case 186: return ';'; /* VK_OEM_1? */
case 222: return '\''; /* VK_OEM_7? */
}
return k;
}
static void
keydown(int k)
{
display_keydown(map_key(k));
}
static void
keyup(int k)
{
display_keyup(map_key(k));
}
/*
* here on any button click, or if mouse dragged while a button down
*/
static void
mousepos(DWORD lp)
{
int x, y;
x = LOWORD(lp);
y = HIWORD(lp);
/* convert to display coordinates */
#if PIX_SIZE > 1
x /= PIX_SIZE;
y /= PIX_SIZE;
#endif
y = ypixels - 1 - y;
/* if window has been stretched, can get out of range bits!! */
if (x >= 0 && x < xpixels && y >= 0 && y < ypixels) {
/* checked by display_add_point() */
ws_lp_x = x;
ws_lp_y = y;
}
}
/* thoingggg!! "message for you sir!!!" */
static LRESULT CALLBACK
patsy(HWND wh, UINT msg, WPARAM wp, LPARAM lp) /* "WndProc" */
{
/* printf("msg %d\n", msg); */
switch (msg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_MOUSEMOVE:
if (wp & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON)) {
#ifdef SWITCH_CURSORS
if (ws_lp_x == -1 && !display_tablet)
SetCursor(cross);
#endif
mousepos(lp);
}
#ifdef SWITCH_CURSORS
else if (ws_lp_x != -1 && !display_tablet)
SetCursor(arrow);
#endif
break; /* return?? */
case WM_LBUTTONDOWN:
display_lp_sw = 1;
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
#ifdef SWITCH_CURSORS
if (!display_tablet)
SetCursor(cross);
#endif
mousepos(lp);
break; /* return?? */
case WM_LBUTTONUP:
display_lp_sw = 0;
case WM_MBUTTONUP:
case WM_RBUTTONUP:
#ifdef SWITCH_CURSORS
if (!display_tablet)
SetCursor(arrow);
#endif
ws_lp_x = ws_lp_y = -1;
break; /* return?? */
case WM_KEYDOWN:
keydown(wp);
break;
case WM_KEYUP:
keyup(wp);
break;
case WM_PAINT:
display_repaint();
break; /* return?? */
}
return DefWindowProc(wh, msg, wp, lp);
}
int
ws_poll(int *valp, int maxus)
{
#ifdef THREADS
/* msgthread handles window events; just delay simulator */
if (maxus > 0)
Sleep((maxus+999)/1000);
#else
MSG msg;
DWORD start;
int maxms = (maxus + 999) / 1000;
for (start = GetTickCount(); GetTickCount() - start < maxms; Sleep(1)) {
/* empty message queue without blocking */
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
#endif
return 1;
}
/* called from non-threaded main program */
int
ws_loop(void (*func)(void *), void *arg)
{
int val;
while (ws_poll(&val, 0))
(*func)(arg);
return val;
}
/* worker for display init */
static void
ws_init2(void) {
WNDCLASS wc;
int h, w;
#ifdef SWITCH_CURSORS
if (!display_tablet) {
arrow = LoadCursor(NULL, IDC_ARROW);
cross = LoadCursor(NULL, IDC_CROSS);
}
#endif
black_brush = GetStockObject(BLACK_BRUSH);
white_brush = GetStockObject(WHITE_BRUSH);
wc.lpszClassName = APP_CLASS;
wc.lpfnWndProc = patsy;
wc.style = CS_OWNDC | CS_VREDRAW | CS_HREDRAW;
/* also CS_NOCLOSE? CS_SAVEBITS? */
wc.hInstance = static_inst = GetModuleHandleA(0);
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
#ifdef SWITCH_CURSORS
wc.hCursor = NULL;
#else
wc.hCursor = display_tablet ? NULL : LoadCursor(NULL, IDC_CROSS);
#endif
wc.hbrBackground = black_brush;
wc.lpszMenuName = APP_MENU;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
/* WNDCLASSEX/RegisterClassEx include hIconSm (small icon) */
RegisterClass(&wc);
/*
* WS_OVERLAPPEDWINDOW=>
* WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME,
* WS_MINIMIZEBOX, WS_MAXIMIZEBOX
*
* WS_CHILD (no menu bar), WS_POPUP (mutually exclusive)
*/
/* empirical crocks to get entire screen; */
w = (xpixels*PIX_SIZE)+6;
h = (ypixels*PIX_SIZE)+32;
/* XXX -- above values work with XP; Phil had +10,+30 */
static_wh = CreateWindow(APP_CLASS, /* registered class name */
window_name, /* window name */
WS_OVERLAPPED, /* style */
CW_USEDEFAULT, CW_USEDEFAULT, /* X,Y */
w, h,
NULL, /* HWND hWndParent */
NULL, /* HMENU hMenu */
static_inst, /* application instance */
NULL); /* lpParam */
ShowWindow(static_wh, SW_SHOW);
UpdateWindow(static_wh);
}
#ifdef THREADS
static volatile int init_done;
static DWORD msgthread_id;
static DWORD WINAPI
msgthread(LPVOID arg)
{
MSG msg;
ws_init2();
/* XXX use a mutex? */
init_done = 1;
while (GetMessage(&msg, NULL, 0, 0) > 0) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
static void
ws_thread_init(void)
{
HANDLE th = CreateThread(NULL, /* sec. attr. */
0, /* stack size */
msgthread,
NULL, /* param */
0, /* flags */
&msgthread_id);
CloseHandle(th);
/* XXX use a mutex; don't wait forever!! */
while (!init_done)
Sleep(200);
}
#endif /* THREADS */
/* called from display layer on first display op */
int
ws_init(char *name, int xp, int yp, int colors, void *dptr)
{
xpixels = xp;
ypixels = yp;
window_name = name;
#ifdef THREADS
ws_thread_init();
#else
ws_init2();
#endif
return 1; /* XXX return errors!! */
}
void ws_shutdown (void)
{
}
void *
ws_color_rgb(int r, int g, int b)
{
/* XXX check for failure??? try GetNearestColor??? */
return CreateSolidBrush(RGB(r/256, g/256, b/256));
}
void *
ws_color_black(void)
{
return black_brush;
}
void *
ws_color_white(void)
{
return white_brush;
}
void
ws_display_point(int x, int y, void *color)
{
HDC dc;
RECT r;
HBRUSH brush = color;
if (x > xpixels || y > ypixels)
return;
y = ypixels - 1 - y; /* invert y, top left origin */
/* top left corner */
r.left = x*PIX_SIZE;
r.top = y*PIX_SIZE;
/* bottom right corner, non-inclusive */
r.right = (x+1)*PIX_SIZE;
r.bottom = (y+1)*PIX_SIZE;
if (brush == NULL)
brush = black_brush;
dc = GetDC(static_wh);
FillRect(dc, &r, brush);
ReleaseDC(static_wh, dc);
}
void
ws_sync(void) {
/* noop */
}
void
ws_beep(void) {
#if 0
/* play SystemDefault sound; does not work over terminal service */
MessageBeep(MB_OK);
#else
/* works over terminal service? Plays default sound/beep on Win9x/ME */
Beep(440, 500); /* Hz, ms. */
#endif
}
unsigned long
os_elapsed(void)
{
static int new;
unsigned long ret;
static DWORD t[2];
/*
* only returns milliseconds, but Sleep()
* only takes milliseconds.
*
* wraps after 49.7 days of uptime.
* DWORD is an unsigned long, so this should be OK
*/
t[new] = GetTickCount();
if (t[!new] == 0)
ret = ~0L; /* +INF */
else
ret = (t[new] - t[!new]) * 1000;
new = !new; /* Ecclesiastes III */
return ret;
}