1 /* ibm1130_gui.c: IBM 1130 CPU simulator Console Display
3 * Based on the SIMH package written by Robert M Supnik
5 * (C) Copyright 2002, Brian Knittel.
6 * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN
7 * RISK basis, there is no warranty of fitness for any purpose, and the rest of the
8 * usual yada-yada. Please keep this notice and the copyright in any distributions
11 * This is not a supported product, but I welcome bug reports and fixes.
12 * Mail to simh@ibm1130.org
14 * 30-Dec-05 BLK Fixed mask for IAR and SAR register display and added display
15 * of Arithmetic Factor, per Carl Claunch.
17 * 09-Apr-04 BLK Changed code to use stock windows cursor IDC_HAND if available
19 * 02-Dec-02 BLK Changed display, added printer and card reader icons
20 * Added drag and drop support for scripts and card decks
21 * Added support for physical card reader and printer (hides icons)
23 * 17-May-02 BLK Pulled out of ibm1130_cpu.c
26 /* ------------------------------------------------------------------------
28 * ------------------------------------------------------------------------ */
33 #include "ibm1130_defs.h"
34 #include "ibm1130res.h"
36 #define UPDATE_BY_TIMER
38 #ifdef UPDATE_BY_TIMER
39 # define UPDATE_INTERVAL 20 /* set to desired number of updates/second */
41 # define UPDATE_INTERVAL 5000 /* GUI: set to 100000/f where f = desired updates/second of 1130 time */
44 #define UNIT_V_CR_EMPTY (UNIT_V_UF + 5) /* NOTE: THESE MUST MATCH THE DEFINITION IN ibm1130_cr.c */
45 #define UNIT_CR_EMPTY (1u << UNIT_V_CR_EMPTY)
46 #define UNIT_V_PHYSICAL (UNIT_V_UF + 9)
47 #define UNIT_PHYSICAL (1u << UNIT_V_PHYSICAL)
49 #define UNIT_V_PHYSICAL_PTR (UNIT_V_UF + 10) /* NOTE: THESE MUST MATCH THE DEFINITION IN ibm1130_prt.c */
50 #define UNIT_PHYSICAL_PTR (1u << UNIT_V_PHYSICAL_PTR)
52 /* I think I had it wrong; Program Load actually does start the processor after
53 * reading in the card?
56 #define PROGRAM_LOAD_STARTS_CPU
58 /* ------------------------------------------------------------------------
59 * Function declarations
60 * ------------------------------------------------------------------------ */
62 t_stat
console_reset (DEVICE
*dptr
);
64 /* ------------------------------------------------------------------------
65 * Console display - on Windows builds (only) this code displays the 1130 console
66 * and toggle switches. It really enhances the experience.
68 * Currently, when the IPS throttle is nonzero, I update the display after every
69 * UPDATE_INTERVAL instructions, plus or minus a random amount to avoid aliased
70 * sampling in loops. When UPDATE_INTERVAL is defined as zero, we update every
71 * instruction no matter what the throttle. This makes the simulator too slow
72 * but it's cool and helpful during development.
73 * ------------------------------------------------------------------------ */
75 #define UNIT_V_DISPLAY (UNIT_V_UF + 0)
76 #define UNIT_DISPLAY (1u << UNIT_V_DISPLAY)
78 MTAB console_mod
[] = {
79 { UNIT_DISPLAY
, 0, "off", "OFF", NULL
},
80 { UNIT_DISPLAY
, UNIT_DISPLAY
, "on", "ON", NULL
},
84 UNIT console_unit
= {UDATA (NULL
, UNIT_DISABLE
|UNIT_DISPLAY
, 0) };
86 DEVICE console_dev
= {
87 "GUI", &console_unit
, NULL
, console_mod
,
89 NULL
, NULL
, console_reset
,
93 /* reset for the "console" display device */
95 extern char *read_line (char *cptr
, int size
, FILE *stream
);
97 extern DEVICE
*find_unit (char *cptr
, UNIT
**uptr
);
99 extern UNIT cr_unit
; /* pointers to 1442 and 1132 (1403) printers */
100 extern UNIT prt_unit
;
103 void update_gui (int force
) {} /* stubs for non-GUI builds */
104 void forms_check (int set
) {}
105 void print_check (int set
) {}
106 void keyboard_select (int select
) {}
107 void keyboard_selected (int select
) {}
108 void disk_ready (int ready
) {}
109 void disk_unlocked (int unlocked
) {}
110 void gui_run (int running
) {}
111 static void init_console_window (void) {}
112 static void destroy_console_window (void) {}
114 t_stat
console_reset (DEVICE
*dptr
) {return SCPE_OK
;}
115 void stuff_cmd (char *cmd
) {}
116 t_bool
stuff_and_wait (char *cmd
, int timeout
, int delay
) {return FALSE
;}
117 char *read_cmdline (char *ptr
, int size
, FILE *stream
) {return read_line(ptr
, size
, stream
);}
118 void remark_cmd (char *remark
) {printf("%s\n", remark
); if (sim_log
) fprintf(sim_log
, "%s\n", remark
);}
121 t_stat
console_reset (DEVICE
*dptr
)
124 SETBIT(console_unit
.flags
, UNIT_DIS
); /* disable the GUI */
125 CLRBIT(console_unit
.flags
, UNIT_DISPLAY
); /* turn the GUI off */
132 /* scp_panic - report fatal internal programming error */
134 void scp_panic (char *msg
)
136 fprintf(stderr
, "%s\n", msg
);
141 /* only _WIN32 is defined right now */
145 #define BUTTON_WIDTH 90
146 #define BUTTON_HEIGHT 50
148 #define IDC_KEYBOARD_SELECT 0
149 #define IDC_DISK_UNLOCK 1
151 #define IDC_PARITY_CHECK 3
153 #define IDC_FILE_READY 5
154 #define IDC_FORMS_CHECK 6
155 #define IDC_POWER_ON 7
157 #define IDC_PROGRAM_START 9
158 #define IDC_PROGRAM_STOP 10
159 #define IDC_LOAD_IAR 11
160 #define IDC_KEYBOARD 12
161 #define IDC_IMM_STOP 13
163 #define IDC_PROGRAM_LOAD 15
165 #define IDC_TEAR 16 /* standard button */
166 #define IDC_1442 17 /* device images */
169 #define LAMPTIME 500 /* 500 msec delay on updating */
170 #define FLASH_TIMER_ID 1
171 #define UPDATE_TIMER_ID 2
173 #define RUNSWITCH_X 689 /* center of the run mode switch dial */
174 #define RUNSWITCH_Y 107
175 #define TOGGLES_X 122 /* left edge of series of toggle switches */
177 #define TXTBOX_X 200 /* text labels showing attached devices */
179 #define TXTBOX_WIDTH 195
180 #define TXTBOX_HEIGHT 12
182 static BOOL class_defined
= FALSE
;
183 static HWND hConsoleWnd
= NULL
;
184 static HBITMAP hBitmap
= NULL
;
185 static HFONT hFont
= NULL
;
186 static HFONT hBtnFont
= NULL
;
187 static HFONT hTinyFont
= NULL
;
188 static HBRUSH hbLampOut
= NULL
;
189 static HBRUSH hbWhite
= NULL
;
190 static HBRUSH hbBlack
= NULL
;
191 static HBRUSH hbGray
= NULL
;
192 static HPEN hSwitchPen
= NULL
;
193 static HPEN hWhitePen
= NULL
;
194 static HPEN hBlackPen
= NULL
;
195 static HPEN hLtGreyPen
= NULL
;
196 static HPEN hGreyPen
= NULL
;
197 static HPEN hDkGreyPen
= NULL
;
198 static int hUpdateTimer
= 0;
199 static int hFlashTimer
= 0;
201 static HCURSOR hcArrow
= NULL
;
202 static HCURSOR hcHand
= NULL
;
203 static HINSTANCE hInstance
;
204 static HDC hCDC
= NULL
;
205 static char szConsoleClassName
[] = "1130CONSOLE";
206 static DWORD PumpID
= 0;
207 static HANDLE hPump
= INVALID_HANDLE_VALUE
;
208 static int bmwid
, bmht
;
209 static HANDLE hbm1442_full
, hbm1442_empty
, hbm1442_eof
, hbm1442_middle
;
210 static HANDLE hbm1132_full
, hbm1132_empty
;
212 static struct tag_btn
{
215 BOOL pushable
, state
;
217 HBRUSH hbrLit
, hbrDark
;
222 0, 0, BUTTON_WIDTH
, BUTTON_HEIGHT
, "KEYBOARD\nSELECT", FALSE
, FALSE
, RGB(255,255,180), NULL
, NULL
, NULL
, TRUE
,
223 0, 1, BUTTON_WIDTH
, BUTTON_HEIGHT
, "DISK\nUNLOCK", FALSE
, TRUE
, RGB(255,255,180), NULL
, NULL
, NULL
, TRUE
,
224 0, 2, BUTTON_WIDTH
, BUTTON_HEIGHT
, "RUN", FALSE
, FALSE
, RGB(0,255,0), NULL
, NULL
, NULL
, TRUE
,
225 0, 3, BUTTON_WIDTH
, BUTTON_HEIGHT
, "PARITY\nCHECK", FALSE
, FALSE
, RGB(255,0,0), NULL
, NULL
, NULL
, TRUE
,
227 1, 0, BUTTON_WIDTH
, BUTTON_HEIGHT
, "", FALSE
, FALSE
, RGB(255,255,180), NULL
, NULL
, NULL
, TRUE
,
228 1, 1, BUTTON_WIDTH
, BUTTON_HEIGHT
, "FILE\nREADY", FALSE
, FALSE
, RGB(0,255,0), NULL
, NULL
, NULL
, TRUE
,
229 1, 2, BUTTON_WIDTH
, BUTTON_HEIGHT
, "FORMS\nCHECK", FALSE
, FALSE
, RGB(255,255,0), NULL
, NULL
, NULL
, TRUE
,
230 1, 3, BUTTON_WIDTH
, BUTTON_HEIGHT
, "POWER\nON", FALSE
, TRUE
, RGB(255,255,180), NULL
, NULL
, NULL
, TRUE
,
232 2, 0, BUTTON_WIDTH
, BUTTON_HEIGHT
, "POWER", TRUE
, FALSE
, RGB(255,255,180), NULL
, NULL
, NULL
, TRUE
,
233 2, 1, BUTTON_WIDTH
, BUTTON_HEIGHT
, "PROGRAM\nSTART", TRUE
, FALSE
, RGB(0,255,0), NULL
, NULL
, NULL
, TRUE
,
234 2, 2, BUTTON_WIDTH
, BUTTON_HEIGHT
, "PROGRAM\nSTOP", TRUE
, FALSE
, RGB(255,0,0), NULL
, NULL
, NULL
, TRUE
,
235 2, 3, BUTTON_WIDTH
, BUTTON_HEIGHT
, "LOAD\nIAR", TRUE
, FALSE
, RGB(0,0,255), NULL
, NULL
, NULL
, TRUE
,
237 3, 0, BUTTON_WIDTH
, BUTTON_HEIGHT
, "KEYBOARD", TRUE
, FALSE
, RGB(255,255,180), NULL
, NULL
, NULL
, TRUE
,
238 3, 1, BUTTON_WIDTH
, BUTTON_HEIGHT
, "IMM\nSTOP", TRUE
, FALSE
, RGB(255,0,0), NULL
, NULL
, NULL
, TRUE
,
239 3, 2, BUTTON_WIDTH
, BUTTON_HEIGHT
, "CHECK\nRESET", TRUE
, FALSE
, RGB(0,0,255), NULL
, NULL
, NULL
, TRUE
,
240 3, 3, BUTTON_WIDTH
, BUTTON_HEIGHT
, "PROGRAM\nLOAD", TRUE
, FALSE
, RGB(0,0,255), NULL
, NULL
, NULL
, TRUE
,
242 TXTBOX_X
+40, TXTBOX_Y
+25, 35, 12, "Tear", TRUE
, FALSE
, 0, NULL
, NULL
, NULL
, FALSE
,
243 635, 238, 110, 110, "EMPTY_1442", TRUE
, FALSE
, 0, NULL
, NULL
, NULL
, FALSE
,
244 635, 366, 110, 110, "EMPTY_1132", TRUE
, FALSE
, 0, NULL
, NULL
, NULL
, FALSE
,
246 #define NBUTTONS (sizeof(btn) / sizeof(btn[0]))
248 #define STATE_1442_EMPTY 0 /* no cards (no file attached) */
249 #define STATE_1442_FULL 1 /* cards in hopper (file attached at BOF) */
250 #define STATE_1442_MIDDLE 2 /* cards in hopper and stacker (file attached, neither EOF nor BOF) */
251 #define STATE_1442_EOF 3 /* cards in stacker (file attached, at EOF) */
252 #define STATE_1442_HIDDEN 4 /* simulator is attached to physical card reader */
254 #define STATE_1132_EMPTY 0 /* no paper hanging out of printer */
255 #define STATE_1132_FULL 1 /* paper hanging out of printer */
256 #define STATE_1132_HIDDEN 2 /* printer is attached to physical printer */
258 static struct tag_txtbox
{
264 TXTBOX_X
, TXTBOX_Y
, "Card Reader", "CR", -1,
265 TXTBOX_X
, TXTBOX_Y
+ 25, "Printer", "PRT", IDC_1132
,
266 TXTBOX_X
, TXTBOX_Y
+ 50, "Disk 1", "DSK0", -1,
267 TXTBOX_X
, TXTBOX_Y
+ 75, "Disk 2", "DSK1", -1,
268 TXTBOX_X
, TXTBOX_Y
+100, "Disk 3", "DSK2", -1,
269 TXTBOX_X
, TXTBOX_Y
+125, "Disk 4", "DSK3", -1,
270 TXTBOX_X
, TXTBOX_Y
+150, "Disk 5", "DSK4", -1,
272 #define NTXTBOXES (sizeof(txtbox) / sizeof(txtbox[0]))
274 #define TXTBOX_BOTTOM (TXTBOX_Y+150)
276 static void init_console_window (void);
277 static void destroy_console_window (void);
278 LRESULT CALLBACK
ConsoleWndProc (HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
);
279 static DWORD WINAPI
Pump (LPVOID arg
);
280 static void accept_dropped_file (HANDLE hDrop
);
281 static void tear_printer (void);
283 #define NIXOBJECT(hObj) if (hObj != NULL) {DeleteObject(hObj); hObj = NULL;}
285 /* ------------------------------------------------------------------------
286 * init_console_window - display the 1130 console. Actually just creates a thread
287 * to run the Pump routine which does the actual work.
288 * ------------------------------------------------------------------------ */
290 static void init_console_window (void)
292 static BOOL did_atexit
= FALSE
;
294 if (hConsoleWnd
!= NULL
)
298 hPump
= CreateThread(NULL
, 0, Pump
, 0, 0, &PumpID
);
301 atexit(destroy_console_window
);
306 /* ------------------------------------------------------------------------
307 * destroy_console_window - delete GDI objects.
308 * ------------------------------------------------------------------------ */
310 static void destroy_console_window (void)
314 if (hConsoleWnd
!= NULL
)
315 SendMessage(hConsoleWnd
, WM_CLOSE
, 0, 0); /* cross thread call is OK */
317 if (hPump
!= INVALID_HANDLE_VALUE
) { /* this is not the most graceful way to do it */
318 TerminateThread(hPump
, 0);
319 hPump
= INVALID_HANDLE_VALUE
;
332 NIXOBJECT(hTinyFont
);
334 NIXOBJECT(hSwitchPen
)
335 NIXOBJECT(hLtGreyPen
)
337 NIXOBJECT(hDkGreyPen
)
339 for (i
= 0; i
< NBUTTONS
; i
++) {
340 NIXOBJECT(btn
[i
].hbrLit
);
341 NIXOBJECT(btn
[i
].hbrDark
);
344 /* if (class_defined) {
345 UnregisterClass(hInstance, szConsoleClassName);
346 class_defined = FALSE;
351 /* ------------------------------------------------------------------------
352 * these variables hold the displayed versions of the system registers
353 * ------------------------------------------------------------------------ */
355 static int shown_iar
= 0, shown_sar
= 0, shown_sbr
= 0, shown_afr
= 0, shown_acc
= 0, shown_ext
= 0;
356 static int shown_op
= 0, shown_tag
= 0, shown_irq
= 0, shown_ccc
= 0, shown_cnd
= 0, shown_wait
= 0;
357 static int shown_ces
= 0, shown_arf
= 0, shown_runmode
= MODE_RUN
;
360 /* ------------------------------------------------------------------------
361 * RedrawRegion - mark a region for redrawing without background erase
362 * ------------------------------------------------------------------------ */
364 static void RedrawRegion (HWND hWnd
, int left
, int top
, int right
, int bottom
)
373 InvalidateRect(hWnd
, &r
, FALSE
);
376 /* ------------------------------------------------------------------------
377 * RepaintRegion - mark a region for redrawing with background erase
378 * ------------------------------------------------------------------------ */
380 static void RepaintRegion (HWND hWnd
, int left
, int top
, int right
, int bottom
)
389 InvalidateRect(hWnd
, &r
, TRUE
);
392 /* ------------------------------------------------------------------------
393 * update_gui - sees if anything on the console display has changed, and invalidates
394 * the changed regions. Then it calls UpdateWindow to force an immediate repaint. This
395 * function (update_gui) should probably not be called every time through the main
396 * instruction loop but it should be called at least whenever wait_state or int_req change, and then
397 * every so many instructions. It's also called after every simh command so manual changes are
398 * reflected instantly.
399 * ------------------------------------------------------------------------ */
401 void update_gui (BOOL force
)
405 static int in_here
= FALSE
;
406 static int32 displayed
= 0;
409 if ((int32
)(console_unit
.flags
& UNIT_DISPLAY
) != displayed
) { /* setting has changed */
410 displayed
= console_unit
.flags
& UNIT_DISPLAY
;
412 init_console_window();
414 destroy_console_window();
417 if (hConsoleWnd
== NULL
)
420 GUI_BEGIN_CRITICAL_SECTION
/* only one thread at a time, please */
422 GUI_END_CRITICAL_SECTION
426 GUI_END_CRITICAL_SECTION
428 CND
= 0; /* combine carry and V as two bits */
434 int_lamps
|= int_req
;
436 int_lamps
|= (0x20 >> ipl
);
438 if (RUNMODE
== MODE_LOAD
)
439 SBR
= CES
; /* in load mode, SBR follows the console switches */
441 if (IAR
!= shown_iar
)
442 {shown_iar
= IAR
; RedrawRegion(hConsoleWnd
, 75, 8, 364, 32);} /* lamps: don't bother erasing bkgnd */
443 if (SAR
!= shown_sar
)
444 {shown_sar
= SAR
; RedrawRegion(hConsoleWnd
, 75, 42, 364, 65);}
445 if (ARF
!= shown_arf
)
446 {shown_arf
= ARF
; RedrawRegion(hConsoleWnd
, 75, 114, 364, 136);}
447 if (ACC
!= shown_acc
)
448 {shown_acc
= ACC
; RedrawRegion(hConsoleWnd
, 75, 141, 364, 164);}
449 if (EXT
!= shown_ext
)
450 {shown_ext
= EXT
; RedrawRegion(hConsoleWnd
, 75, 174, 364, 197);}
451 if (SBR
!= shown_sbr
)
452 {shown_sbr
= SBR
; RedrawRegion(hConsoleWnd
, 75, 77, 364, 97);}
454 {shown_op
= OP
; RedrawRegion(hConsoleWnd
, 501, 8, 595, 32);}
455 if (TAG
!= shown_tag
)
456 {shown_tag
= TAG
; RedrawRegion(hConsoleWnd
, 501, 77, 595, 97);}
458 if (int_lamps
!= shown_irq
)
459 {shown_irq
= int_lamps
; RedrawRegion(hConsoleWnd
, 501, 108, 595, 130);}
461 if (CCC
!= shown_ccc
)
462 {shown_ccc
= CCC
; RedrawRegion(hConsoleWnd
, 501, 141, 595, 164);}
463 if (CND
!= shown_cnd
)
464 {shown_cnd
= CND
; RedrawRegion(hConsoleWnd
, 501, 174, 595, 197);}
465 if ((wait_state
|wait_lamp
) != shown_wait
)
466 {shown_wait
= (wait_state
|wait_lamp
); RedrawRegion(hConsoleWnd
, 380, 77, 414, 97);}
467 if (CES
!= shown_ces
)
468 {shown_ces
= CES
; RepaintRegion(hConsoleWnd
, TOGGLES_X
-7, 230, TOGGLES_X
+360, 275);} /* console entry sw: do erase bkgnd */
469 if (RUNMODE
!= shown_runmode
)
470 {shown_runmode
= RUNMODE
;RepaintRegion(hConsoleWnd
, RUNSWITCH_X
-50, RUNSWITCH_Y
-50, RUNSWITCH_X
+50, RUNSWITCH_Y
+50);}
474 /* this loop works with lamp buttons that are calculated on-the-fly only */
475 for (i
= 0; i
< NBUTTONS
; i
++) {
481 state
= hFlashTimer
|| (running
&& ! wait_state
);
484 /* this button is always off
485 case IDC_PARITY_CHECK
488 /* these buttons are enabled/disabled directly
491 case IDC_FORMS_CHECK:
492 case IDC_KEYBOARD_SELECT:
493 case IDC_DISK_UNLOCK:
499 if (state
!= btn
[i
].state
) { /* state has changed */
500 EnableWindow(btn
[i
].hBtn
, state
);
501 btn
[i
].state
= state
;
505 if (force
) { /* if force flag is set, update text region */
506 SetRect(&xin
, TXTBOX_X
, TXTBOX_Y
, TXTBOX_X
+TXTBOX_WIDTH
, TXTBOX_BOTTOM
+2*TXTBOX_HEIGHT
);
507 InvalidateRect(hConsoleWnd
, &xin
, TRUE
);
510 state
= ((cr_unit
.flags
& UNIT_ATT
) == 0) ? STATE_1442_EMPTY
:
511 (cr_unit
.flags
& UNIT_PHYSICAL
) ? STATE_1442_HIDDEN
:
512 (cr_unit
.flags
& UNIT_CR_EMPTY
) ? STATE_1442_EOF
:
513 cr_unit
.pos
? STATE_1442_MIDDLE
:
516 if (state
!= btn
[IDC_1442
].state
) {
517 if (state
== STATE_1442_HIDDEN
)
518 ShowWindow(btn
[IDC_1442
].hBtn
, SW_HIDE
);
520 if (btn
[IDC_1442
].state
== STATE_1442_HIDDEN
)
521 ShowWindow(btn
[IDC_1442
].hBtn
, SW_SHOWNA
);
523 SendMessage(btn
[IDC_1442
].hBtn
, STM_SETIMAGE
, IMAGE_BITMAP
,
525 (state
== STATE_1442_FULL
) ? hbm1442_full
:
526 (state
== STATE_1442_MIDDLE
) ? hbm1442_middle
:
527 (state
== STATE_1442_EOF
) ? hbm1442_eof
:
531 btn
[IDC_1442
].state
= state
;
534 state
= ((prt_unit
.flags
& UNIT_ATT
) == 0) ? STATE_1132_EMPTY
:
535 (prt_unit
.flags
& UNIT_PHYSICAL_PTR
) ? STATE_1132_HIDDEN
:
536 prt_unit
.pos
? STATE_1132_FULL
:
539 if (state
!= btn
[IDC_1132
].state
) {
540 if (state
== STATE_1132_HIDDEN
)
541 ShowWindow(btn
[IDC_1132
].hBtn
, SW_HIDE
);
543 if (btn
[IDC_1132
].state
== STATE_1132_HIDDEN
)
544 ShowWindow(btn
[IDC_1132
].hBtn
, SW_SHOWNA
);
546 SendMessage(btn
[IDC_1132
].hBtn
, STM_SETIMAGE
, IMAGE_BITMAP
,
548 (state
== STATE_1132_FULL
) ? hbm1132_full
: hbm1132_empty
));
551 btn
[IDC_1132
].state
= state
;
557 WNDPROC oldButtonProc
= NULL
;
559 /* ------------------------------------------------------------------------
560 * ------------------------------------------------------------------------ */
562 LRESULT CALLBACK
ButtonProc (HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
566 i
= GetWindowLong(hWnd
, GWL_ID
);
568 if (! btn
[i
].pushable
) {
569 if (uMsg
== WM_LBUTTONDOWN
|| uMsg
== WM_LBUTTONUP
|| uMsg
== WM_LBUTTONDBLCLK
)
573 if ((TCHAR
) wParam
== ' ')
577 return CallWindowProc(oldButtonProc
, hWnd
, uMsg
, wParam
, lParam
);
580 /* ------------------------------------------------------------------------
581 * ------------------------------------------------------------------------ */
583 static int occurs (char *txt
, char ch
)
594 /* ------------------------------------------------------------------------
595 * turns out to get properly colored buttons you have to paint them yourself. Sheesh.
596 * On the plus side, this lets do a better job of aligning the button text than
597 * the button would by itself.
598 * ------------------------------------------------------------------------ */
600 void PaintButton (LPDRAWITEMSTRUCT dis
)
602 int i
= dis
->CtlID
, nc
, nlines
, x
, y
, dy
;
603 BOOL down
= dis
->itemState
& ODS_SELECTED
;
610 if (! BETWEEN(i
, 0, NBUTTONS
-1))
613 if (! btn
[i
].subclassed
)
616 FillRect(dis
->hDC
, &dis
->rcItem
, ((btn
[i
].pushable
|| power
) && IsWindowEnabled(btn
[i
].hBtn
)) ? btn
[i
].hbrLit
: btn
[i
].hbrDark
);
618 if (! btn
[i
].pushable
) {
619 hOldPen
= SelectObject(dis
->hDC
, hBlackPen
);
620 MoveToEx(dis
->hDC
, dis
->rcItem
.left
, dis
->rcItem
.top
, NULL
);
621 LineTo(dis
->hDC
, dis
->rcItem
.right
-1, dis
->rcItem
.top
);
622 LineTo(dis
->hDC
, dis
->rcItem
.right
-1, dis
->rcItem
.bottom
-1);
623 LineTo(dis
->hDC
, dis
->rcItem
.left
, dis
->rcItem
.bottom
-1);
624 LineTo(dis
->hDC
, dis
->rcItem
.left
, dis
->rcItem
.top
);
627 /* do the three-D thing */
628 hOldPen
= SelectObject(dis
->hDC
, hDkGreyPen
);
629 MoveToEx(dis
->hDC
, dis
->rcItem
.left
, dis
->rcItem
.bottom
-2, NULL
);
630 LineTo(dis
->hDC
, dis
->rcItem
.left
, dis
->rcItem
.top
);
631 LineTo(dis
->hDC
, dis
->rcItem
.right
-1, dis
->rcItem
.top
);
633 SelectObject(dis
->hDC
, hWhitePen
);
634 MoveToEx(dis
->hDC
, dis
->rcItem
.left
, dis
->rcItem
.bottom
-1, NULL
);
635 LineTo(dis
->hDC
, dis
->rcItem
.right
-1, dis
->rcItem
.bottom
-1);
636 LineTo(dis
->hDC
, dis
->rcItem
.right
-1, dis
->rcItem
.top
);
638 SelectObject(dis
->hDC
, hGreyPen
);
639 MoveToEx(dis
->hDC
, dis
->rcItem
.left
+1, dis
->rcItem
.bottom
-3, NULL
);
640 LineTo(dis
->hDC
, dis
->rcItem
.left
+1, dis
->rcItem
.top
+1);
641 LineTo(dis
->hDC
, dis
->rcItem
.right
-3, dis
->rcItem
.top
+1);
644 hOldPen
= SelectObject(dis
->hDC
, hWhitePen
);
645 MoveToEx(dis
->hDC
, dis
->rcItem
.left
, dis
->rcItem
.bottom
-2, NULL
);
646 LineTo(dis
->hDC
, dis
->rcItem
.left
, dis
->rcItem
.top
);
647 LineTo(dis
->hDC
, dis
->rcItem
.right
-1, dis
->rcItem
.top
);
649 SelectObject(dis
->hDC
, hDkGreyPen
);
650 MoveToEx(dis
->hDC
, dis
->rcItem
.left
, dis
->rcItem
.bottom
-1, NULL
);
651 LineTo(dis
->hDC
, dis
->rcItem
.right
-1, dis
->rcItem
.bottom
-1);
652 LineTo(dis
->hDC
, dis
->rcItem
.right
-1, dis
->rcItem
.top
);
654 SelectObject(dis
->hDC
, hGreyPen
);
655 MoveToEx(dis
->hDC
, dis
->rcItem
.left
+1, dis
->rcItem
.bottom
-2, NULL
);
656 LineTo(dis
->hDC
, dis
->rcItem
.right
-2, dis
->rcItem
.bottom
-2);
657 LineTo(dis
->hDC
, dis
->rcItem
.right
-2, dis
->rcItem
.top
+1);
660 SelectObject(dis
->hDC
, hOldPen
);
662 hOldFont
= SelectObject(dis
->hDC
, hBtnFont
);
663 oldAlign
= SetTextAlign(dis
->hDC
, TA_CENTER
|TA_TOP
);
664 oldBk
= SetBkMode(dis
->hDC
, TRANSPARENT
);
667 nlines
= occurs(txt
, '\n')+1;
668 x
= (dis
->rcItem
.left
+ dis
->rcItem
.right
) / 2;
669 y
= (dis
->rcItem
.top
+ dis
->rcItem
.bottom
) / 2;
672 y
= y
- (nlines
*dy
)/2;
680 for (nc
= 0, tstart
= txt
; *txt
&& *txt
!= '\n'; txt
++, nc
++)
683 TextOut(dis
->hDC
, x
, y
, tstart
, nc
);
692 SetTextAlign(dis
->hDC
, oldAlign
);
693 SetBkMode(dis
->hDC
, oldBk
);
694 SelectObject(dis
->hDC
, hOldFont
);
697 /* ------------------------------------------------------------------------
698 * ------------------------------------------------------------------------ */
700 HWND
CreateSubclassedButton (HWND hwParent
, int i
)
706 y
= bmht
- (4*BUTTON_HEIGHT
) + BUTTON_HEIGHT
* btn
[i
].y
;
707 x
= (btn
[i
].x
< 2) ? (btn
[i
].x
*BUTTON_WIDTH
) : (598 - (4-btn
[i
].x
)*BUTTON_WIDTH
);
709 if ((hBtn
= CreateWindow("BUTTON", btn
[i
].txt
, WS_CHILD
|WS_VISIBLE
|BS_CENTER
|BS_MULTILINE
|BS_OWNERDRAW
,
710 x
, y
, BUTTON_WIDTH
, BUTTON_HEIGHT
, hwParent
, (HMENU
) i
, hInstance
, NULL
)) == NULL
)
715 if (oldButtonProc
== NULL
)
716 oldButtonProc
= (WNDPROC
) GetWindowLong(hBtn
, GWL_WNDPROC
);
718 btn
[i
].hbrLit
= CreateSolidBrush(btn
[i
].clr
);
720 if (! btn
[i
].pushable
) {
721 r
= GetRValue(btn
[i
].clr
) / 4;
722 g
= GetGValue(btn
[i
].clr
) / 4;
723 b
= GetBValue(btn
[i
].clr
) / 4;
725 btn
[i
].hbrDark
= CreateSolidBrush(RGB(r
,g
,b
));
726 EnableWindow(hBtn
, FALSE
);
729 SetWindowLong(hBtn
, GWL_WNDPROC
, (LONG
) ButtonProc
);
733 /* ------------------------------------------------------------------------
734 * Pump - thread that takes care of the console window. It has to be a separate thread so that it gets
735 * execution time even when the simulator is compute-bound or IO-blocked. This routine creates the window
736 * and runs a standard Windows message pump. The window function does the actual display work.
737 * ------------------------------------------------------------------------ */
739 static DWORD WINAPI
Pump (LPVOID arg
)
749 hActWnd
= GetForegroundWindow();
751 if (! class_defined
) { /* register Window class */
752 hInstance
= GetModuleHandle(NULL
);
754 memset(&cd
, 0, sizeof(cd
));
755 cd
.style
= CS_NOCLOSE
;
756 cd
.lpfnWndProc
= ConsoleWndProc
;
759 cd
.hInstance
= hInstance
;
761 cd
.hCursor
= hcArrow
;
762 cd
.hbrBackground
= NULL
;
763 cd
.lpszMenuName
= NULL
;
764 cd
.lpszClassName
= szConsoleClassName
;
766 if (! RegisterClass(&cd
)) {
771 class_defined
= TRUE
;
774 hbWhite
= GetStockObject(WHITE_BRUSH
); /* create or fetch useful GDI objects */
775 hbBlack
= GetStockObject(BLACK_BRUSH
); /* create or fetch useful GDI objects */
776 hbGray
= GetStockObject(GRAY_BRUSH
);
777 hSwitchPen
= CreatePen(PS_SOLID
, 5, RGB(255,255,255));
779 hWhitePen
= GetStockObject(WHITE_PEN
);
780 hBlackPen
= GetStockObject(BLACK_PEN
);
781 hLtGreyPen
= CreatePen(PS_SOLID
, 1, RGB(190,190,190));
782 hGreyPen
= CreatePen(PS_SOLID
, 1, RGB(128,128,128));
783 hDkGreyPen
= CreatePen(PS_SOLID
, 1, RGB(64,64,64));
785 hcArrow
= LoadCursor(NULL
, IDC_ARROW
);
787 hcHand
= LoadCursor(NULL
, IDC_HAND
); /* use stock object provided by Windows */
789 hcHand
= LoadCursor(hInstance
, MAKEINTRESOURCE(IDC_MYHAND
));
791 hcHand
= LoadCursor(hInstance
, MAKEINTRESOURCE(IDC_MYHAND
));
795 hBitmap
= LoadBitmap(hInstance
, MAKEINTRESOURCE(IDB_CONSOLE
));
796 if (hbLampOut
== NULL
)
797 hbLampOut
= CreateSolidBrush(RGB(50,50,50));
799 hFont
= CreateFont(-10, 0, 0, 0, FW_NORMAL
, 0, 0, 0, DEFAULT_CHARSET
, OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, FIXED_PITCH
, FF_SWISS
, "Arial");
800 if (hBtnFont
== NULL
)
801 hBtnFont
= CreateFont(-12, 0, 0, 0, FW_NORMAL
, 0, 0, 0, DEFAULT_CHARSET
, OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, FIXED_PITCH
, FF_SWISS
, "Arial");
802 if (hTinyFont
== NULL
)
803 hTinyFont
= CreateFont(-10, 0, 0, 0, FW_NORMAL
, 0, 0, 0, DEFAULT_CHARSET
, OUT_DEFAULT_PRECIS
, CLIP_DEFAULT_PRECIS
, FIXED_PITCH
, FF_SWISS
, "Arial");
805 if (hConsoleWnd
== NULL
) { /* create window */
806 if ((hConsoleWnd
= CreateWindow(szConsoleClassName
, "IBM 1130", WS_OVERLAPPED
|WS_CLIPCHILDREN
, 0, 0, 200, 200, NULL
, NULL
, hInstance
, NULL
)) == NULL
) {
811 DragAcceptFiles(hConsoleWnd
, TRUE
); /* let it accept dragged files (scripts) */
814 GetObject(hBitmap
, sizeof(bm
), &bm
); /* get bitmap size */
818 for (i
= 0; i
< NBUTTONS
; i
++) {
819 if (! btn
[i
].subclassed
)
822 CreateSubclassedButton(hConsoleWnd
, i
);
823 if (! btn
[i
].pushable
)
824 EnableWindow(btn
[i
].hBtn
, btn
[i
].state
);
827 /* This isn't needed anymore, now that we have the big printer icon -- it acts like a button now
829 * btn[i].hBtn = CreateWindow("BUTTON", btn[i].txt, WS_CHILD|WS_VISIBLE|BS_CENTER,
830 * btn[i].x, btn[i].y, btn[i].wx, btn[i].wy, hConsoleWnd, (HMENU) i, hInstance, NULL);
832 * SendMessage(btn[i].hBtn, WM_SETFONT, (WPARAM) hTinyFont, TRUE);
835 hbm1442_full
= LoadBitmap(hInstance
, "FULL_1442");
836 hbm1442_empty
= LoadBitmap(hInstance
, "EMPTY_1442");
837 hbm1442_eof
= LoadBitmap(hInstance
, "EOF_1442");
838 hbm1442_middle
= LoadBitmap(hInstance
, "MIDDLE_1442");
839 hbm1132_full
= LoadBitmap(hInstance
, "FULL_1132");
840 hbm1132_empty
= LoadBitmap(hInstance
, "EMPTY_1132");
844 btn
[i
].hBtn
= CreateWindow("STATIC", btn
[i
].txt
, WS_CHILD
|WS_VISIBLE
|SS_BITMAP
|SS_SUNKEN
|WS_BORDER
|SS_REALSIZEIMAGE
|SS_NOTIFY
,
845 btn
[i
].x
, btn
[i
].y
, btn
[i
].wx
, btn
[i
].wy
, hConsoleWnd
, (HMENU
) i
, hInstance
, NULL
);
846 btn
[i
].state
= STATE_1442_EMPTY
;
848 wx
= SendMessage(btn
[i
].hBtn
, STM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
) hbm1442_empty
);
852 btn
[i
].hBtn
= CreateWindow("STATIC", btn
[i
].txt
, WS_CHILD
|WS_VISIBLE
|SS_BITMAP
|SS_SUNKEN
|WS_BORDER
|SS_REALSIZEIMAGE
|SS_NOTIFY
,
853 btn
[i
].x
, btn
[i
].y
, btn
[i
].wx
, btn
[i
].wy
, hConsoleWnd
, (HMENU
) i
, hInstance
, NULL
);
854 btn
[i
].state
= FALSE
;
856 wx
= SendMessage(btn
[i
].hBtn
, STM_SETIMAGE
, IMAGE_BITMAP
, (LPARAM
) hbm1132_empty
);
858 GetWindowRect(hConsoleWnd
, &r
); /* get window size as created */
859 wx
= r
.right
- r
.left
+ 1;
860 wy
= r
.bottom
- r
.top
+ 1;
862 if (hCDC
== NULL
) { /* get a memory DC and select the bitmap into ti */
863 hDC
= GetDC(hConsoleWnd
);
864 hCDC
= CreateCompatibleDC(hDC
);
865 SelectObject(hCDC
, hBitmap
);
866 ReleaseDC(hConsoleWnd
, hDC
);
869 GetClientRect(hConsoleWnd
, &r
);
870 wx
= (wx
- r
.right
- 1) + bmwid
; /* compute new desired size based on how client area came out */
871 wy
= (wy
- r
.bottom
- 1) + bmht
;
872 MoveWindow(hConsoleWnd
, 0, 0, wx
, wy
, FALSE
); /* resize window */
874 ShowWindow(hConsoleWnd
, SW_SHOWNOACTIVATE
); /* display it */
875 UpdateWindow(hConsoleWnd
);
877 if (hActWnd
!= NULL
) { /* bring console (sim) window back to top */
878 GetWindowRect(hConsoleWnd
, &r
);
879 ShowWindow(hActWnd
, SW_NORMAL
); /* and move it just below the display window */
880 SetWindowPos(hActWnd
, HWND_TOP
, 0, r
.bottom
, 0, 0, SWP_NOSIZE
);
881 GetWindowRect(hActWnd
, &ra
);
882 if (ra
.bottom
>= GetSystemMetrics(SM_CYSCREEN
)) { /* resize if it goes of bottom of screen */
883 ra
.bottom
= GetSystemMetrics(SM_CYSCREEN
) - 1;
884 SetWindowPos(hActWnd
, 0, 0, 0, ra
.right
-ra
.left
+1, ra
.bottom
-ra
.top
+1, SWP_NOZORDER
|SWP_NOMOVE
);
888 if (running
) /* if simulator is already running, start update timer */
891 while (GetMessage(&msg
, hConsoleWnd
, 0, 0)) { /* message pump - this basically loops forevermore */
892 TranslateMessage(&msg
);
893 DispatchMessage(&msg
);
896 if (hConsoleWnd
!= NULL
) {
897 DragAcceptFiles(hConsoleWnd
, FALSE
); /* unregister as drag/drop target */
898 DestroyWindow(hConsoleWnd
); /* but if a quit message got posted, clean up */
906 /* ------------------------------------------------------------------------
907 * DrawBits - starting at position (x,y), draw lamps for nbits bits of word 'bits', looking only at masked bits
908 * ------------------------------------------------------------------------ */
910 static void DrawBits (HDC hDC
, int x
, int y
, int bits
, int nbits
, int mask
, char *syms
)
912 int i
, b
= 0x0001 << (nbits
-1);
914 for (i
= 0; i
< nbits
; i
++, b
>>= 1) {
915 if (mask
& b
) { /* select white or black lettering then write 2 chars */
916 SetTextColor(hDC
, (b
& bits
&& power
) ? RGB(255,255,255) : RGB(0,0,0));
917 TextOut(hDC
, x
, y
, syms
, 2);
919 syms
+= 2; /* go to next symbol pair */
922 x
+= 15; /* step between lamps */
928 x
+= 10; /* step over nibble divisions on left side */
935 /* ------------------------------------------------------------------------
936 * DrawToggles - display the console sense switches
937 * ------------------------------------------------------------------------ */
940 static void DrawToggles (HDC hDC
, int bits
)
944 for (b
= 0x8000, x
= TOGGLES_X
; b
!= 0; b
>>= 1) {
945 if (shown_ces
& b
) { /* up */
946 SelectObject(hDC
, hbWhite
);
947 Rectangle(hDC
, x
, 232, x
+9, 240);
948 SelectObject(hDC
, hbGray
);
949 Rectangle(hDC
, x
, 239, x
+9, 255);
952 SelectObject(hDC
, hbWhite
);
953 Rectangle(hDC
, x
, 263, x
+9, 271);
954 SelectObject(hDC
, hbGray
);
955 Rectangle(hDC
, x
, 248, x
+9, 264);
958 x
+= (b
& 0x1111) ? 31 : 21;
962 /* ------------------------------------------------------------------------
963 * DrawRunmode - draw the run mode rotary switch's little tip
964 * ------------------------------------------------------------------------ */
966 void DrawRunmode (HDC hDC
, int mode
)
968 double angle
= (mode
*45. + 90.) * 3.1415926 / 180.; /* convert mode position to angle in radians */
969 double ca
, sa
; /* sine and cosine */
976 x0
= RUNSWITCH_X
+ (int) (20.*ca
+ 0.5); /* inner radius */
977 y0
= RUNSWITCH_Y
- (int) (20.*sa
+ 0.5);
978 x1
= RUNSWITCH_X
+ (int) (25.*ca
+ 0.5); /* outer radius */
979 y1
= RUNSWITCH_Y
- (int) (25.*sa
+ 0.5);
981 hOldPen
= SelectObject(hDC
, hSwitchPen
);
983 MoveToEx(hDC
, x0
, y0
, NULL
);
986 SelectObject(hDC
, hOldPen
);
989 /* ------------------------------------------------------------------------
990 * HandleClick - handle mouse clicks on the console window. Now we just
991 * look at the console sense switches. Actual says this is a real click, rather
992 * than a mouse-region test. Return value TRUE means the cursor is over a hotspot.
993 * ------------------------------------------------------------------------ */
995 static BOOL
HandleClick (HWND hWnd
, int xh
, int yh
, BOOL actual
, BOOL rightclick
)
999 for (b
= 0x8000, x
= TOGGLES_X
; b
!= 0; b
>>= 1) {
1000 if (BETWEEN(xh
, x
-3, x
+8+3) && BETWEEN(yh
, 230, 275)) {
1002 CES
^= b
; /* a hit. Invert the bit and redisplay */
1007 x
+= (b
& 0x1111) ? 31 : 21;
1010 if (BETWEEN(xh
, RUNSWITCH_X
-50, RUNSWITCH_X
+50) && BETWEEN(yh
, RUNSWITCH_Y
-50, RUNSWITCH_Y
+50)) { /* hit near rotary switch */
1011 ang
= (int) (atan2(RUNSWITCH_X
-xh
, RUNSWITCH_Y
-yh
)*180./3.1415926); /* this does implicit 90 deg rotation by the way */
1012 r
= (int) sqrt((xh
-RUNSWITCH_X
)*(xh
-RUNSWITCH_X
)+(yh
-RUNSWITCH_Y
)*(yh
-RUNSWITCH_Y
));
1014 for (i
= MODE_LOAD
; i
<= MODE_INT_RUN
; i
++) {
1015 if (BETWEEN(ang
, i
*45-12, i
*45+12)) {
1030 /* ------------------------------------------------------------------------
1031 * DrawConsole - refresh the console display. (This routine could be sped up by intersecting
1032 * the various components' bounding rectangles with the repaint rectangle. The bounding rects
1033 * could be put into an array and used both here and in the refresh routine).
1035 * RedrawRegion -> force repaint w/o background redraw. used for lamps which are drawn in the same place in either state
1036 * RepaintRegion-> repaint with background redraw. Used for toggles which change position.
1037 * ------------------------------------------------------------------------ */
1039 static void DrawConsole (HDC hDC
, PAINTSTRUCT
*ps
)
1041 static char digits
[] = " 0 1 2 3 4 5 6 7 8 9101112131415";
1042 static char cccs
[] = "3216 8 4 2 1";
1043 static char cnds
[] = " C V";
1044 static char waits
[] = " W";
1045 HFONT hOldFont
, hOldBrush
;
1051 char nametemp
[50], *dispname
;
1053 hOldFont
= SelectObject(hDC
, hFont
); /* use that tiny font */
1054 hOldBrush
= SelectObject(hDC
, hbWhite
);
1056 SetBkMode(hDC
, TRANSPARENT
); /* overlay letters w/o changing background */
1058 DrawBits(hDC
, 76, 15, shown_iar
, 16, mem_mask
, digits
); /* register holds only 15 bits */
1059 DrawBits(hDC
, 76, 48, shown_sar
, 16, mem_mask
, digits
); /* but let's display only used bits */
1060 DrawBits(hDC
, 76, 81, shown_sbr
, 16, 0xFFFF, digits
);
1061 DrawBits(hDC
, 76, 114, shown_arf
, 16, 0xFFFF, digits
);
1062 DrawBits(hDC
, 76, 147, shown_acc
, 16, 0xFFFF, digits
);
1063 DrawBits(hDC
, 76, 180, shown_ext
, 16, 0xFFFF, digits
);
1065 DrawBits(hDC
, 506, 15, shown_op
, 5, 0x001F, digits
);
1066 DrawBits(hDC
, 506, 81, shown_tag
, 4, 0x0007, digits
);
1067 DrawBits(hDC
, 506, 114, shown_irq
, 6, 0x003F, digits
);
1068 DrawBits(hDC
, 506, 147, shown_ccc
, 6, 0x003F, cccs
);
1069 DrawBits(hDC
, 506, 180, shown_cnd
, 2, 0x0003, cnds
);
1071 DrawBits(hDC
, 390, 81, shown_wait
?1:0,1, 0x0001, waits
);
1073 DrawToggles(hDC
, shown_ces
);
1075 DrawRunmode(hDC
, shown_runmode
);
1077 SelectObject(hDC
, hOldFont
);
1078 SelectObject(hDC
, hOldBrush
);
1080 SetBkColor(hDC
, RGB(0,0,0));
1082 SetRect(&xin
, TXTBOX_X
, TXTBOX_Y
, TXTBOX_X
+TXTBOX_WIDTH
, TXTBOX_BOTTOM
+TXTBOX_HEIGHT
);
1083 if (IntersectRect(&xout
, &xin
, &ps
->rcPaint
)) {
1084 hOldFont
= SelectObject(hDC
, hTinyFont
);
1086 for (i
= 0; i
< NTXTBOXES
; i
++) {
1089 dptr
= find_unit(txtbox
[i
].unitname
, &uptr
);
1090 if (dptr
!= NULL
&& uptr
!= NULL
) {
1091 if (uptr
->flags
& UNIT_DIS
) {
1092 SetTextColor(hDC
, RGB(128,0,0));
1094 else if (uptr
->flags
& UNIT_ATT
) {
1095 SetTextColor(hDC
, RGB(0,0,255));
1096 if ((n
= strlen(uptr
->filename
)) > 30) {
1097 strcpy(nametemp
, "...");
1098 strcpy(nametemp
+3, uptr
->filename
+n
-30);
1099 dispname
= nametemp
;
1102 dispname
= uptr
->filename
;
1104 TextOut(hDC
, txtbox
[i
].x
+25, txtbox
[i
].y
+TXTBOX_HEIGHT
, dispname
, strlen(dispname
));
1105 SetTextColor(hDC
, RGB(255,255,255));
1109 SetTextColor(hDC
, RGB(128,128,128));
1111 TextOut(hDC
, txtbox
[i
].x
, txtbox
[i
].y
, txtbox
[i
].txt
, strlen(txtbox
[i
].txt
));
1114 if (txtbox
[i
].idctrl
>= 0)
1115 EnableWindow(btn
[txtbox
[i
].idctrl
].hBtn
, enab
);
1118 SelectObject(hDC
, hOldFont
);
1122 /* ------------------------------------------------------------------------
1123 * Handles button presses. Remember that this occurs in the context of
1124 * the Pump thread, not the simulator thread.
1125 * ------------------------------------------------------------------------ */
1127 void flash_run (void)
1129 EnableWindow(btn
[IDC_RUN
].hBtn
, TRUE
); /* enable the run lamp */
1131 if (hFlashTimer
!= 0)
1132 KillTimer(hConsoleWnd
, FLASH_TIMER_ID
); /* (re)schedule lamp update */
1134 hFlashTimer
= SetTimer(hConsoleWnd
, FLASH_TIMER_ID
, LAMPTIME
, NULL
);
1137 void gui_run (int running
)
1139 if (running
&& hUpdateTimer
== 0 && hConsoleWnd
!= NULL
) {
1140 hUpdateTimer
= SetTimer(hConsoleWnd
, UPDATE_TIMER_ID
, 1000/UPDATE_INTERVAL
, NULL
);
1142 else if (hUpdateTimer
!= 0 && ! running
) {
1143 KillTimer(hConsoleWnd
, UPDATE_TIMER_ID
);
1146 flash_run(); /* keep run lamp active for a while after we stop running */
1149 void HandleCommand (HWND hWnd
, WORD wNotify
, WORD idCtl
, HWND hwCtl
)
1154 case IDC_POWER
: /* toggle system power */
1157 if (running
&& ! power
) { /* turning off */
1158 reason
= STOP_POWER_OFF
;
1159 /* wait for execution thread to exit */
1160 /* this prevents message pump from running, which unfortunately locks up
1161 * the emulator thread when it calls gui_run(FALSE) which calls EnableWindow on the Run lamp
1167 btn
[IDC_POWER_ON
].state
= power
;
1168 EnableWindow(btn
[IDC_POWER_ON
].hBtn
, power
);
1170 for (i
= 0; i
< NBUTTONS
; i
++) /* repaint all of the lamps */
1171 if (! btn
[i
].pushable
)
1172 InvalidateRect(btn
[i
].hBtn
, NULL
, TRUE
);
1176 case IDC_PROGRAM_START
: /* begin execution */
1185 case MODE_DISP
: /* display core and advance IAR */
1188 flash_run(); /* illuminate run lamp for .5 sec */
1191 case MODE_LOAD
: /* store to core and advance IAR */
1200 case IDC_PROGRAM_STOP
:
1201 if (running
) { /* potential race condition here */
1202 GUI_BEGIN_CRITICAL_SECTION
1203 SETBIT(con_dsw
, CPU_DSW_PROGRAM_STOP
);
1204 SETBIT(ILSW
[5], ILSW_5_INT_RUN_PROGRAM_STOP
);
1205 int_req
|= INT_REQ_5
; /* note: calc_ints() is not needed in this case */
1206 int_lamps
|= INT_REQ_5
;
1207 GUI_END_CRITICAL_SECTION
1213 IAR
= CES
& mem_mask
; /* set IAR from console entry switches */
1217 case IDC_KEYBOARD
: /* toggle between console/keyboard mode */
1222 reason
= STOP_IMMEDIATE
; /* terminate execution without setting wait_mode */
1223 /* wait for execution thread to exit */
1224 /* this prevents message pump from running, which unfortunately locks up
1225 * the emulator thread when it calls gui_run(FALSE) which calls EnableWindow on the Run lamp
1233 if (! running
) { /* check-reset is disabled while running */
1235 forms_check(0); /* clear forms-check status */
1240 case IDC_PROGRAM_LOAD
:
1241 if (! running
) { /* if card reader is attached to a file, do cold start read of one card */
1242 IAR
= 0; /* reset IAR */
1243 #ifdef PROGRAM_LOAD_STARTS_CPU
1244 stuff_cmd("boot cr");
1246 if (cr_boot(0, NULL
) != SCPE_OK
) /* load boot card */
1247 remark_cmd("IPL failed");
1252 case IDC_TEAR
: /* "tear off printer output" */
1253 case IDC_1132
: /* do same if they click on the printer icon */
1254 if (btn
[IDC_1132
].state
&& (wNotify
== STN_CLICKED
|| wNotify
== STN_DBLCLK
))
1259 if (btn
[IDC_1442
].state
== STATE_1442_FULL
|| wNotify
== STN_DBLCLK
)
1260 stuff_cmd("detach cr");
1261 else if (btn
[IDC_1442
].state
!= STATE_1442_EMPTY
&& wNotify
== STN_CLICKED
) {
1271 /* ------------------------------------------------------------------------
1272 * ConsoleWndProc - window process for the console display
1273 * ------------------------------------------------------------------------ */
1275 LRESULT CALLBACK
ConsoleWndProc (HWND hWnd
, UINT uMsg
, WPARAM wParam
, LPARAM lParam
)
1280 RECT clip
, xsect
, rbmp
;
1285 DestroyWindow(hWnd
);
1295 GetClipBox(hDC
, &clip
);
1296 SetRect(&rbmp
, 0, 0, bmwid
, bmht
);
1297 if (IntersectRect(&xsect
, &clip
, &rbmp
))
1298 BitBlt(hDC
, xsect
.left
, xsect
.top
, xsect
.right
-xsect
.left
+1, xsect
.bottom
-xsect
.top
+1, hCDC
, xsect
.left
, xsect
.top
, SRCCOPY
);
1299 return TRUE
; /* let Paint do this so we know what the update region is (ps.rcPaint) */
1302 hDC
= BeginPaint(hWnd
, &ps
);
1303 DrawConsole(hDC
, &ps
);
1304 EndPaint(hWnd
, &ps
);
1307 case WM_COMMAND
: /* button click */
1308 HandleCommand(hWnd
, HIWORD(wParam
), LOWORD(wParam
), (HWND
) lParam
);
1311 case WM_CTLCOLOREDIT
: /* text color for edit controls */
1312 SetBkColor((HDC
) wParam
, RGB(0,0,0));
1313 SetTextColor((HDC
) wParam
, RGB(255,255,255));
1317 PaintButton((LPDRAWITEMSTRUCT
) lParam
);
1322 ScreenToClient(hWnd
, &p
);
1323 SetCursor(HandleClick(hWnd
, p
.x
, p
.y
, FALSE
, FALSE
) ? hcHand
: hcArrow
);
1326 case WM_LBUTTONDOWN
:
1327 HandleClick(hWnd
, LOWORD(lParam
), HIWORD(lParam
), TRUE
, FALSE
);
1330 case WM_RBUTTONDOWN
:
1331 HandleClick(hWnd
, LOWORD(lParam
), HIWORD(lParam
), TRUE
, TRUE
);
1334 case WM_CTLCOLORBTN
:
1335 i
= GetWindowLong((HWND
) lParam
, GWL_ID
);
1336 if (BETWEEN(i
, 0, NBUTTONS
-1))
1337 return (LRESULT
) (power
&& IsWindowEnabled((HWND
) lParam
) ? btn
[i
].hbrLit
: btn
[i
].hbrDark
);
1340 if (wParam
== FLASH_TIMER_ID
&& hFlashTimer
!= 0) {
1341 KillTimer(hWnd
, FLASH_TIMER_ID
);
1348 accept_dropped_file((HANDLE
) wParam
); /* console window - dragged file is a script or card deck */
1352 return DefWindowProc(hWnd
, uMsg
, wParam
, lParam
);
1358 enum {PRINTER_OK
= 0, FORMS_CHECK
= 1, PRINT_CHECK
= 2, BOTH_CHECK
= 3} printerstatus
= PRINTER_OK
;
1360 void forms_check (int set
)
1362 COLORREF oldcolor
= btn
[IDC_FORMS_CHECK
].clr
;
1365 SETBIT(printerstatus
, FORMS_CHECK
);
1367 CLRBIT(printerstatus
, FORMS_CHECK
);
1369 btn
[IDC_FORMS_CHECK
].clr
= (printerstatus
& PRINT_CHECK
) ? RGB(255,0,0) : RGB(255,255,0);
1371 btn
[IDC_FORMS_CHECK
].state
= printerstatus
;
1373 if (btn
[IDC_FORMS_CHECK
].hBtn
!= NULL
) {
1374 EnableWindow(btn
[IDC_FORMS_CHECK
].hBtn
, printerstatus
);
1376 if (btn
[IDC_FORMS_CHECK
].clr
!= oldcolor
)
1377 InvalidateRect(btn
[IDC_FORMS_CHECK
].hBtn
, NULL
, TRUE
); /* change color in any case */
1381 void print_check (int set
)
1383 COLORREF oldcolor
= btn
[IDC_FORMS_CHECK
].clr
;
1386 SETBIT(printerstatus
, PRINT_CHECK
);
1388 CLRBIT(printerstatus
, PRINT_CHECK
);
1390 btn
[IDC_FORMS_CHECK
].clr
= (printerstatus
& PRINT_CHECK
) ? RGB(255,0,0) : RGB(255,255,0);
1392 btn
[IDC_FORMS_CHECK
].state
= printerstatus
;
1394 if (btn
[IDC_FORMS_CHECK
].hBtn
!= NULL
) {
1395 EnableWindow(btn
[IDC_FORMS_CHECK
].hBtn
, printerstatus
);
1397 if (btn
[IDC_FORMS_CHECK
].clr
!= oldcolor
)
1398 InvalidateRect(btn
[IDC_FORMS_CHECK
].hBtn
, NULL
, TRUE
); /* change color in any case */
1402 void keyboard_selected (int select
)
1404 btn
[IDC_KEYBOARD_SELECT
].state
= select
;
1406 if (btn
[IDC_KEYBOARD_SELECT
].hBtn
!= NULL
)
1407 EnableWindow(btn
[IDC_KEYBOARD_SELECT
].hBtn
, select
);
1410 void disk_ready (int ready
)
1412 btn
[IDC_FILE_READY
].state
= ready
;
1414 if (btn
[IDC_FILE_READY
].hBtn
!= NULL
)
1415 EnableWindow(btn
[IDC_FILE_READY
].hBtn
, ready
);
1418 void disk_unlocked (int unlocked
)
1420 btn
[IDC_DISK_UNLOCK
].state
= unlocked
;
1422 if (btn
[IDC_DISK_UNLOCK
].hBtn
!= NULL
)
1423 EnableWindow(btn
[IDC_DISK_UNLOCK
].hBtn
, unlocked
);
1426 static void accept_dropped_file (HANDLE hDrop
)
1429 char fname
[MAX_PATH
], cmd
[MAX_PATH
+50], *deckfile
;
1434 nfiles
= DragQueryFile(hDrop
, 0xFFFFFFFF, NULL
, 0); /* get file count, */
1435 DragQueryFile(hDrop
, 0, fname
, sizeof(fname
)); /* get first filename */
1436 DragQueryPoint(hDrop
, &pt
); /* get location of drop */
1439 if (nfiles
<= 0) /* hmm, this seems unlikely to occur, but better check */
1442 if (running
) { /* can only accept a drop while processor is stopped */
1447 if ((hWndDrop
= ChildWindowFromPoint(hConsoleWnd
, pt
)) == btn
[IDC_1442
].hBtn
)
1448 cardreader
= TRUE
; /* file was dropped onto 1442 card reader */
1449 else if (hWndDrop
== NULL
|| hWndDrop
== hConsoleWnd
)
1450 cardreader
= FALSE
; /* file was dropped onto console window, not a button */
1452 MessageBeep(0); /* file was dropped onto another button */
1456 if (nfiles
> 1) { /* oops, we wouldn't know what order to read them in */
1457 MessageBox(hConsoleWnd
, "You may only drop one file at a time", "", MB_OK
);
1461 /* if shift key is down, prepend @ to name (make it a deck file) */
1462 deckfile
= ((GetKeyState(VK_SHIFT
) & 0x8000) && cardreader
) ? "@" : "";
1464 sprintf(cmd
, "%s \"%s%s\"", cardreader
? "attach cr" : "do", deckfile
, fname
);
1468 static void tear_printer (void)
1470 char cmd
[MAX_PATH
+100], filename
[MAX_PATH
];
1472 if ((prt_unit
.flags
& UNIT_ATT
) == 0)
1475 strcpy(filename
, prt_unit
.filename
); /* save current attached filename */
1477 if (! stuff_and_wait("detach prt", 1000, 0)) /* detach it */
1480 sprintf(cmd
, "view \"%s\"", filename
); /* spawn notepad to view it */
1481 if (! stuff_and_wait(cmd
, 3000, 500))
1484 remove(filename
); /* delete the file */
1486 sprintf(cmd
, "attach prt \"%s\"", filename
); /* reattach */
1491 if ((hBtn
= CreateWindow("BUTTON", btn
[i
].txt
, WS_CHILD
|WS_VISIBLE
|BS_CENTER
|BS_MULTILINE
|BS_OWNERDRAW
,
1492 x
, y
, BUTTON_WIDTH
, BUTTON_HEIGHT
, hwParent
, (HMENU
) i
, hInstance
, NULL
)) == NULL
)
1497 CRITICAL_SECTION critsect
;
1499 void begin_critical_section (void)
1501 static BOOL mustinit
= TRUE
;
1504 InitializeCriticalSection(&critsect
);
1508 EnterCriticalSection(&critsect
);
1511 void end_critical_section (void)
1513 LeaveCriticalSection(&critsect
);
1517 # define MIN(a,b) (((a) <= (b)) ? (a) : (b))
1520 /* win32 - use a separate thread to read command lines so the GUI
1521 * can insert commands as well */
1523 static HANDLE hCmdThread
= NULL
;
1524 static DWORD iCmdThreadID
= 0;
1525 static HANDLE hCmdReadEvent
= NULL
;
1526 static HANDLE hCmdReadyEvent
= NULL
;
1527 static BOOL scp_stuffed
= FALSE
, scp_reading
= FALSE
;
1528 static char cmdbuffer
[256];
1530 /* CmdThread - separate thread to read commands from stdin upon request */
1532 static DWORD WINAPI
CmdThread (LPVOID arg
)
1535 WaitForSingleObject(hCmdReadEvent
, INFINITE
); /* wait for request */
1536 read_line(cmdbuffer
, sizeof(cmdbuffer
), stdin
); /* read one line */
1537 scp_stuffed
= FALSE
; /* say how we got it */
1538 scp_reading
= FALSE
;
1539 SetEvent(hCmdReadyEvent
); /* notify main thread a line is ready */
1544 char *read_cmdline (char *ptr
, int size
, FILE *stream
)
1548 if (hCmdThread
== NULL
) { /* set up command-reading thread */
1549 if ((hCmdReadEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
)) == NULL
)
1550 scp_panic("Can't create command line read event");
1552 if ((hCmdReadyEvent
= CreateEvent(NULL
, FALSE
, FALSE
, NULL
)) == NULL
)
1553 scp_panic("Can't create command line ready event");
1554 /* start up the command thread */
1555 if ((hCmdThread
= CreateThread(NULL
, 0, CmdThread
, NULL
, 0, &iCmdThreadID
)) == NULL
)
1556 scp_panic("Unable to create command line reading thread");
1561 SetEvent(hCmdReadEvent
); /* let read thread get one line */
1562 WaitForSingleObject(hCmdReadyEvent
, INFINITE
); /* wait for read thread or GUI to respond */
1563 strncpy(ptr
, cmdbuffer
, MIN(size
, sizeof(cmdbuffer
))); /* copy line to caller's buffer */
1565 for (cptr
= ptr
; isspace(*cptr
); cptr
++) /* absorb spaces */
1568 if (scp_stuffed
) { /* stuffed command needs to be echoed */
1569 printf("%s\n", cptr
);
1570 if (sim_log
) fprintf(sim_log
, "%s\n", cptr
);
1576 /* stuff_cmd - force a command into the read_cmdline output buffer. Called asynchronously by GUI */
1578 void stuff_cmd (char *cmd
)
1580 strcpy(cmdbuffer
, cmd
); /* save the string */
1581 scp_stuffed
= TRUE
; /* note where it came from */
1582 scp_reading
= FALSE
;
1583 ResetEvent(hCmdReadEvent
); /* clear read request event */
1584 SetEvent(hCmdReadyEvent
); /* notify main thread a line is ready */
1587 /* my_yield - process GUI messages. It's not apparent why stuff_and_wait would block,
1588 * since it sleeps in the GUI thread while scp runs in the main thread. However,
1589 * at the end of every command scp calls update_gui, which can result in messages
1590 * being sent to the GUI thread. So, the GUI thread has to process messages while
1591 * stuff_and_wait is waiting.
1593 static void my_yield (void)
1597 while (PeekMessage(&msg
, NULL
, 0, 0, PM_REMOVE
)) {
1598 TranslateMessage(&msg
);
1599 DispatchMessage(&msg
);
1603 /* stuff_and_wait -- stuff a command and wait for the emulator to process the command
1604 * and come back to prompt for another
1607 t_bool
stuff_and_wait (char *cmd
, int timeout
, int delay
)
1609 scp_reading
= FALSE
;
1613 while (! scp_reading
) {
1623 if ((timeout
-= 50) <= 0)
1635 /* remark_cmd - print a remark from inside a command processor. This routine takes
1636 * into account the possiblity that the command might have been stuffed, in which
1637 * case the sim> prompt needs to be reprinted.
1640 void remark_cmd (char *remark
)
1644 if (sim_log
) putc('\n', sim_log
);
1647 printf("%s\n", remark
);
1648 if (sim_log
) fprintf(sim_log
, "%s\n", remark
);
1652 if (sim_log
) fprintf(sim_log
, "sim> ");
1656 #endif /* _WIN32 defined */
1657 #endif /* GUI_SUPPORT defined */