mirror of
https://github.com/simh/simh.git
synced 2026-04-15 16:11:13 +00:00
Initial public version of TX-0 for SIMH
Integrate TX-0 simulation into SIMH.
This commit is contained in:
418
display/win32.c
Normal file
418
display/win32.c
Normal file
@@ -0,0 +1,418 @@
|
||||
/*
|
||||
* $Id: win32.c,v 1.38 2004/02/07 06:32:01 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 "display.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 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)
|
||||
;
|
||||
}
|
||||
#endif /* THREADS */
|
||||
|
||||
/* called from display layer on first display op */
|
||||
int
|
||||
ws_init(char *name, int xp, int yp, int colors)
|
||||
{
|
||||
xpixels = xp;
|
||||
ypixels = yp;
|
||||
window_name = name;
|
||||
|
||||
#ifdef THREADS
|
||||
ws_thread_init();
|
||||
#else
|
||||
ws_init2();
|
||||
#endif
|
||||
return 1; /* XXX return errors!! */
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user