First Commit of my working state
[simh.git] / Ibm1130 / ibm1130_gui.c
CommitLineData
196ba1fc
PH
1/* ibm1130_gui.c: IBM 1130 CPU simulator Console Display\r
2 *\r
3 * Based on the SIMH package written by Robert M Supnik\r
4 *\r
5 * (C) Copyright 2002, Brian Knittel.\r
6 * You may freely use this program, but: it offered strictly on an AS-IS, AT YOUR OWN\r
7 * RISK basis, there is no warranty of fitness for any purpose, and the rest of the\r
8 * usual yada-yada. Please keep this notice and the copyright in any distributions\r
9 * or modifications.\r
10 *\r
11 * This is not a supported product, but I welcome bug reports and fixes.\r
12 * Mail to simh@ibm1130.org\r
13 *\r
14 * 30-Dec-05 BLK Fixed mask for IAR and SAR register display and added display\r
15 * of Arithmetic Factor, per Carl Claunch.\r
16 *\r
17 * 09-Apr-04 BLK Changed code to use stock windows cursor IDC_HAND if available\r
18 *\r
19 * 02-Dec-02 BLK Changed display, added printer and card reader icons\r
20 * Added drag and drop support for scripts and card decks\r
21 * Added support for physical card reader and printer (hides icons)\r
22 *\r
23 * 17-May-02 BLK Pulled out of ibm1130_cpu.c\r
24 */\r
25\r
26/* ------------------------------------------------------------------------\r
27 * Definitions\r
28 * ------------------------------------------------------------------------ */\r
29\r
30#include <stdarg.h>\r
31#include <math.h>\r
32\r
33#include "ibm1130_defs.h"\r
34#include "ibm1130res.h"\r
35\r
36#define UPDATE_BY_TIMER\r
37\r
38#ifdef UPDATE_BY_TIMER\r
39# define UPDATE_INTERVAL 20 /* set to desired number of updates/second */\r
40#else\r
41# define UPDATE_INTERVAL 5000 /* GUI: set to 100000/f where f = desired updates/second of 1130 time */\r
42#endif\r
43\r
44#define UNIT_V_CR_EMPTY (UNIT_V_UF + 5) /* NOTE: THESE MUST MATCH THE DEFINITION IN ibm1130_cr.c */\r
45#define UNIT_CR_EMPTY (1u << UNIT_V_CR_EMPTY)\r
46#define UNIT_V_PHYSICAL (UNIT_V_UF + 9)\r
47#define UNIT_PHYSICAL (1u << UNIT_V_PHYSICAL)\r
48\r
49#define UNIT_V_PHYSICAL_PTR (UNIT_V_UF + 10) /* NOTE: THESE MUST MATCH THE DEFINITION IN ibm1130_prt.c */\r
50#define UNIT_PHYSICAL_PTR (1u << UNIT_V_PHYSICAL_PTR)\r
51\r
52/* I think I had it wrong; Program Load actually does start the processor after\r
53 * reading in the card?\r
54 */\r
55\r
56#define PROGRAM_LOAD_STARTS_CPU\r
57\r
58/* ------------------------------------------------------------------------\r
59 * Function declarations\r
60 * ------------------------------------------------------------------------ */\r
61\r
62t_stat console_reset (DEVICE *dptr);\r
63\r
64/* ------------------------------------------------------------------------ \r
65 * Console display - on Windows builds (only) this code displays the 1130 console\r
66 * and toggle switches. It really enhances the experience.\r
67 *\r
68 * Currently, when the IPS throttle is nonzero, I update the display after every\r
69 * UPDATE_INTERVAL instructions, plus or minus a random amount to avoid aliased\r
70 * sampling in loops. When UPDATE_INTERVAL is defined as zero, we update every\r
71 * instruction no matter what the throttle. This makes the simulator too slow\r
72 * but it's cool and helpful during development.\r
73 * ------------------------------------------------------------------------ */\r
74\r
75#define UNIT_V_DISPLAY (UNIT_V_UF + 0)\r
76#define UNIT_DISPLAY (1u << UNIT_V_DISPLAY)\r
77\r
78MTAB console_mod[] = {\r
79 { UNIT_DISPLAY, 0, "off", "OFF", NULL },\r
80 { UNIT_DISPLAY, UNIT_DISPLAY, "on", "ON", NULL },\r
81 { 0 }\r
82};\r
83\r
84UNIT console_unit = {UDATA (NULL, UNIT_DISABLE|UNIT_DISPLAY, 0) };\r
85\r
86DEVICE console_dev = {\r
87 "GUI", &console_unit, NULL, console_mod,\r
88 1, 16, 16, 1, 16, 16,\r
89 NULL, NULL, console_reset,\r
90 NULL, NULL, NULL\r
91};\r
92\r
93/* reset for the "console" display device */\r
94\r
95extern char *read_line (char *cptr, int size, FILE *stream);\r
96extern FILE *sim_log;\r
97extern DEVICE *find_unit (char *cptr, UNIT **uptr);\r
98\r
99extern UNIT cr_unit; /* pointers to 1442 and 1132 (1403) printers */\r
100extern UNIT prt_unit;\r
101\r
102#ifndef GUI_SUPPORT\r
103 void update_gui (int force) {} /* stubs for non-GUI builds */\r
104 void forms_check (int set) {}\r
105 void print_check (int set) {}\r
106 void keyboard_select (int select) {}\r
107 void keyboard_selected (int select) {}\r
108 void disk_ready (int ready) {}\r
109 void disk_unlocked (int unlocked) {}\r
110 void gui_run (int running) {} \r
111 static void init_console_window (void) {}\r
112 static void destroy_console_window (void) {}\r
113\r
114 t_stat console_reset (DEVICE *dptr) {return SCPE_OK;}\r
115 void stuff_cmd (char *cmd) {}\r
116 t_bool stuff_and_wait (char *cmd, int timeout, int delay) {return FALSE;}\r
117 char *read_cmdline (char *ptr, int size, FILE *stream) {return read_line(ptr, size, stream);}\r
118 void remark_cmd (char *remark) {printf("%s\n", remark); if (sim_log) fprintf(sim_log, "%s\n", remark);}\r
119#else\r
120\r
121t_stat console_reset (DEVICE *dptr)\r
122{\r
123 if (! sim_gui) {\r
124 SETBIT(console_unit.flags, UNIT_DIS); /* disable the GUI */\r
125 CLRBIT(console_unit.flags, UNIT_DISPLAY); /* turn the GUI off */\r
126 }\r
127\r
128 update_gui(FALSE);\r
129 return SCPE_OK;\r
130}\r
131\r
132/* scp_panic - report fatal internal programming error */\r
133\r
134void scp_panic (char *msg)\r
135{\r
136 fprintf(stderr, "%s\n", msg);\r
137 exit(1);\r
138}\r
139\r
140#ifdef _WIN32\r
141 /* only _WIN32 is defined right now */\r
142\r
143#include <windows.h>\r
144\r
145#define BUTTON_WIDTH 90\r
146#define BUTTON_HEIGHT 50\r
147\r
148#define IDC_KEYBOARD_SELECT 0\r
149#define IDC_DISK_UNLOCK 1\r
150#define IDC_RUN 2\r
151#define IDC_PARITY_CHECK 3\r
152#define IDC_UNUSED 4\r
153#define IDC_FILE_READY 5\r
154#define IDC_FORMS_CHECK 6\r
155#define IDC_POWER_ON 7\r
156#define IDC_POWER 8\r
157#define IDC_PROGRAM_START 9\r
158#define IDC_PROGRAM_STOP 10\r
159#define IDC_LOAD_IAR 11\r
160#define IDC_KEYBOARD 12\r
161#define IDC_IMM_STOP 13\r
162#define IDC_RESET 14\r
163#define IDC_PROGRAM_LOAD 15\r
164\r
165#define IDC_TEAR 16 /* standard button */\r
166#define IDC_1442 17 /* device images */\r
167#define IDC_1132 18\r
168\r
169#define LAMPTIME 500 /* 500 msec delay on updating */\r
170#define FLASH_TIMER_ID 1\r
171#define UPDATE_TIMER_ID 2\r
172\r
173#define RUNSWITCH_X 689 /* center of the run mode switch dial */\r
174#define RUNSWITCH_Y 107\r
175#define TOGGLES_X 122 /* left edge of series of toggle switches */\r
176\r
177#define TXTBOX_X 200 /* text labels showing attached devices */\r
178#define TXTBOX_Y 300\r
179#define TXTBOX_WIDTH 195\r
180#define TXTBOX_HEIGHT 12\r
181\r
182static BOOL class_defined = FALSE;\r
183static HWND hConsoleWnd = NULL;\r
184static HBITMAP hBitmap = NULL;\r
185static HFONT hFont = NULL;\r
186static HFONT hBtnFont = NULL;\r
187static HFONT hTinyFont = NULL;\r
188static HBRUSH hbLampOut = NULL;\r
189static HBRUSH hbWhite = NULL;\r
190static HBRUSH hbBlack = NULL;\r
191static HBRUSH hbGray = NULL;\r
192static HPEN hSwitchPen = NULL;\r
193static HPEN hWhitePen = NULL;\r
194static HPEN hBlackPen = NULL;\r
195static HPEN hLtGreyPen = NULL;\r
196static HPEN hGreyPen = NULL;\r
197static HPEN hDkGreyPen = NULL;\r
198static int hUpdateTimer = 0;\r
199static int hFlashTimer = 0;\r
200\r
201static HCURSOR hcArrow = NULL;\r
202static HCURSOR hcHand = NULL;\r
203static HINSTANCE hInstance;\r
204static HDC hCDC = NULL;\r
205static char szConsoleClassName[] = "1130CONSOLE";\r
206static DWORD PumpID = 0;\r
207static HANDLE hPump = INVALID_HANDLE_VALUE;\r
208static int bmwid, bmht;\r
209static HANDLE hbm1442_full, hbm1442_empty, hbm1442_eof, hbm1442_middle;\r
210static HANDLE hbm1132_full, hbm1132_empty;\r
211\r
212static struct tag_btn {\r
213 int x, y, wx, wy;\r
214 char *txt;\r
215 BOOL pushable, state;\r
216 COLORREF clr;\r
217 HBRUSH hbrLit, hbrDark;\r
218 HWND hBtn;\r
219 BOOL subclassed;\r
220\r
221} btn[] = {\r
222 0, 0, BUTTON_WIDTH, BUTTON_HEIGHT, "KEYBOARD\nSELECT", FALSE, FALSE, RGB(255,255,180), NULL, NULL, NULL, TRUE,\r
223 0, 1, BUTTON_WIDTH, BUTTON_HEIGHT, "DISK\nUNLOCK", FALSE, TRUE, RGB(255,255,180), NULL, NULL, NULL, TRUE,\r
224 0, 2, BUTTON_WIDTH, BUTTON_HEIGHT, "RUN", FALSE, FALSE, RGB(0,255,0), NULL, NULL, NULL, TRUE,\r
225 0, 3, BUTTON_WIDTH, BUTTON_HEIGHT, "PARITY\nCHECK", FALSE, FALSE, RGB(255,0,0), NULL, NULL, NULL, TRUE,\r
226\r
227 1, 0, BUTTON_WIDTH, BUTTON_HEIGHT, "", FALSE, FALSE, RGB(255,255,180), NULL, NULL, NULL, TRUE,\r
228 1, 1, BUTTON_WIDTH, BUTTON_HEIGHT, "FILE\nREADY", FALSE, FALSE, RGB(0,255,0), NULL, NULL, NULL, TRUE,\r
229 1, 2, BUTTON_WIDTH, BUTTON_HEIGHT, "FORMS\nCHECK", FALSE, FALSE, RGB(255,255,0), NULL, NULL, NULL, TRUE,\r
230 1, 3, BUTTON_WIDTH, BUTTON_HEIGHT, "POWER\nON", FALSE, TRUE, RGB(255,255,180), NULL, NULL, NULL, TRUE,\r
231\r
232 2, 0, BUTTON_WIDTH, BUTTON_HEIGHT, "POWER", TRUE, FALSE, RGB(255,255,180), NULL, NULL, NULL, TRUE,\r
233 2, 1, BUTTON_WIDTH, BUTTON_HEIGHT, "PROGRAM\nSTART", TRUE, FALSE, RGB(0,255,0), NULL, NULL, NULL, TRUE,\r
234 2, 2, BUTTON_WIDTH, BUTTON_HEIGHT, "PROGRAM\nSTOP", TRUE, FALSE, RGB(255,0,0), NULL, NULL, NULL, TRUE,\r
235 2, 3, BUTTON_WIDTH, BUTTON_HEIGHT, "LOAD\nIAR", TRUE, FALSE, RGB(0,0,255), NULL, NULL, NULL, TRUE,\r
236\r
237 3, 0, BUTTON_WIDTH, BUTTON_HEIGHT, "KEYBOARD", TRUE, FALSE, RGB(255,255,180), NULL, NULL, NULL, TRUE,\r
238 3, 1, BUTTON_WIDTH, BUTTON_HEIGHT, "IMM\nSTOP", TRUE, FALSE, RGB(255,0,0), NULL, NULL, NULL, TRUE,\r
239 3, 2, BUTTON_WIDTH, BUTTON_HEIGHT, "CHECK\nRESET", TRUE, FALSE, RGB(0,0,255), NULL, NULL, NULL, TRUE,\r
240 3, 3, BUTTON_WIDTH, BUTTON_HEIGHT, "PROGRAM\nLOAD", TRUE, FALSE, RGB(0,0,255), NULL, NULL, NULL, TRUE,\r
241 \r
242 TXTBOX_X+40, TXTBOX_Y+25, 35, 12, "Tear", TRUE, FALSE, 0, NULL, NULL, NULL, FALSE,\r
243 635, 238, 110, 110, "EMPTY_1442", TRUE, FALSE, 0, NULL, NULL, NULL, FALSE,\r
244 635, 366, 110, 110, "EMPTY_1132", TRUE, FALSE, 0, NULL, NULL, NULL, FALSE,\r
245};\r
246#define NBUTTONS (sizeof(btn) / sizeof(btn[0]))\r
247\r
248#define STATE_1442_EMPTY 0 /* no cards (no file attached) */\r
249#define STATE_1442_FULL 1 /* cards in hopper (file attached at BOF) */\r
250#define STATE_1442_MIDDLE 2 /* cards in hopper and stacker (file attached, neither EOF nor BOF) */\r
251#define STATE_1442_EOF 3 /* cards in stacker (file attached, at EOF) */\r
252#define STATE_1442_HIDDEN 4 /* simulator is attached to physical card reader */\r
253\r
254#define STATE_1132_EMPTY 0 /* no paper hanging out of printer */\r
255#define STATE_1132_FULL 1 /* paper hanging out of printer */\r
256#define STATE_1132_HIDDEN 2 /* printer is attached to physical printer */\r
257\r
258static struct tag_txtbox {\r
259 int x, y;\r
260 char *txt;\r
261 char *unitname;\r
262 int idctrl;\r
263} txtbox[] = {\r
264 TXTBOX_X, TXTBOX_Y, "Card Reader", "CR", -1,\r
265 TXTBOX_X, TXTBOX_Y+ 25, "Printer", "PRT", IDC_1132,\r
266 TXTBOX_X, TXTBOX_Y+ 50, "Disk 1", "DSK0", -1,\r
267 TXTBOX_X, TXTBOX_Y+ 75, "Disk 2", "DSK1", -1,\r
268 TXTBOX_X, TXTBOX_Y+100, "Disk 3", "DSK2", -1,\r
269 TXTBOX_X, TXTBOX_Y+125, "Disk 4", "DSK3", -1,\r
270 TXTBOX_X, TXTBOX_Y+150, "Disk 5", "DSK4", -1,\r
271};\r
272#define NTXTBOXES (sizeof(txtbox) / sizeof(txtbox[0]))\r
273\r
274#define TXTBOX_BOTTOM (TXTBOX_Y+150)\r
275\r
276static void init_console_window (void);\r
277static void destroy_console_window (void);\r
278LRESULT CALLBACK ConsoleWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);\r
279static DWORD WINAPI Pump (LPVOID arg);\r
280static void accept_dropped_file (HANDLE hDrop);\r
281static void tear_printer (void);\r
282\r
283#define NIXOBJECT(hObj) if (hObj != NULL) {DeleteObject(hObj); hObj = NULL;}\r
284\r
285/* ------------------------------------------------------------------------ \r
286 * init_console_window - display the 1130 console. Actually just creates a thread \r
287 * to run the Pump routine which does the actual work.\r
288 * ------------------------------------------------------------------------ */\r
289\r
290static void init_console_window (void)\r
291{\r
292 static BOOL did_atexit = FALSE;\r
293\r
294 if (hConsoleWnd != NULL)\r
295 return;\r
296\r
297 if (PumpID == 0)\r
298 hPump = CreateThread(NULL, 0, Pump, 0, 0, &PumpID);\r
299\r
300 if (! did_atexit) {\r
301 atexit(destroy_console_window);\r
302 did_atexit = TRUE;\r
303 }\r
304}\r
305\r
306/* ------------------------------------------------------------------------ \r
307 * destroy_console_window - delete GDI objects.\r
308 * ------------------------------------------------------------------------ */\r
309\r
310static void destroy_console_window (void)\r
311{\r
312 int i;\r
313\r
314 if (hConsoleWnd != NULL)\r
315 SendMessage(hConsoleWnd, WM_CLOSE, 0, 0); /* cross thread call is OK */\r
316\r
317 if (hPump != INVALID_HANDLE_VALUE) { /* this is not the most graceful way to do it */\r
318 TerminateThread(hPump, 0);\r
319 hPump = INVALID_HANDLE_VALUE;\r
320 PumpID = 0;\r
321 hConsoleWnd = NULL;\r
322 }\r
323 if (hCDC != NULL) {\r
324 DeleteDC(hCDC);\r
325 hCDC = NULL;\r
326 }\r
327\r
328 NIXOBJECT(hBitmap)\r
329 NIXOBJECT(hbLampOut)\r
330 NIXOBJECT(hFont)\r
331 NIXOBJECT(hBtnFont);\r
332 NIXOBJECT(hTinyFont);\r
333 NIXOBJECT(hcHand)\r
334 NIXOBJECT(hSwitchPen)\r
335 NIXOBJECT(hLtGreyPen)\r
336 NIXOBJECT(hGreyPen)\r
337 NIXOBJECT(hDkGreyPen)\r
338\r
339 for (i = 0; i < NBUTTONS; i++) {\r
340 NIXOBJECT(btn[i].hbrLit);\r
341 NIXOBJECT(btn[i].hbrDark);\r
342 }\r
343\r
344/* if (class_defined) {\r
345 UnregisterClass(hInstance, szConsoleClassName);\r
346 class_defined = FALSE;\r
347 }\r
348*/\r
349}\r
350\r
351/* ------------------------------------------------------------------------ \r
352 * these variables hold the displayed versions of the system registers \r
353 * ------------------------------------------------------------------------ */\r
354\r
355static int shown_iar = 0, shown_sar = 0, shown_sbr = 0, shown_afr = 0, shown_acc = 0, shown_ext = 0;\r
356static int shown_op = 0, shown_tag = 0, shown_irq = 0, shown_ccc = 0, shown_cnd = 0, shown_wait = 0;\r
357static int shown_ces = 0, shown_arf = 0, shown_runmode = MODE_RUN;\r
358static int CND;\r
359\r
360/* ------------------------------------------------------------------------ \r
361 * RedrawRegion - mark a region for redrawing without background erase\r
362 * ------------------------------------------------------------------------ */\r
363\r
364static void RedrawRegion (HWND hWnd, int left, int top, int right, int bottom)\r
365{\r
366 RECT r;\r
367\r
368 r.left = left;\r
369 r.top = top;\r
370 r.right = right;\r
371 r.bottom = bottom;\r
372\r
373 InvalidateRect(hWnd, &r, FALSE);\r
374}\r
375\r
376/* ------------------------------------------------------------------------ \r
377 * RepaintRegion - mark a region for redrawing with background erase\r
378 * ------------------------------------------------------------------------ */\r
379\r
380static void RepaintRegion (HWND hWnd, int left, int top, int right, int bottom)\r
381{\r
382 RECT r;\r
383\r
384 r.left = left;\r
385 r.top = top;\r
386 r.right = right;\r
387 r.bottom = bottom;\r
388\r
389 InvalidateRect(hWnd, &r, TRUE);\r
390}\r
391\r
392/* ------------------------------------------------------------------------ \r
393 * update_gui - sees if anything on the console display has changed, and invalidates \r
394 * the changed regions. Then it calls UpdateWindow to force an immediate repaint. This\r
395 * function (update_gui) should probably not be called every time through the main\r
396 * instruction loop but it should be called at least whenever wait_state or int_req change, and then\r
397 * every so many instructions. It's also called after every simh command so manual changes are\r
398 * reflected instantly.\r
399 * ------------------------------------------------------------------------ */\r
400\r
401void update_gui (BOOL force)\r
402{ \r
403 int i;\r
404 BOOL state;\r
405 static int in_here = FALSE;\r
406 static int32 displayed = 0;\r
407 RECT xin;\r
408\r
409 if ((int32)(console_unit.flags & UNIT_DISPLAY) != displayed) { /* setting has changed */\r
410 displayed = console_unit.flags & UNIT_DISPLAY;\r
411 if (displayed)\r
412 init_console_window();\r
413 else\r
414 destroy_console_window();\r
415 }\r
416\r
417 if (hConsoleWnd == NULL)\r
418 return;\r
419\r
420 GUI_BEGIN_CRITICAL_SECTION /* only one thread at a time, please */\r
421 if (in_here) {\r
422 GUI_END_CRITICAL_SECTION\r
423 return;\r
424 }\r
425 in_here = TRUE;\r
426 GUI_END_CRITICAL_SECTION\r
427\r
428 CND = 0; /* combine carry and V as two bits */\r
429 if (C)\r
430 CND |= 2;\r
431 if (V)\r
432 CND |= 1;\r
433\r
434 int_lamps |= int_req;\r
435 if (ipl >= 0)\r
436 int_lamps |= (0x20 >> ipl);\r
437\r
438 if (RUNMODE == MODE_LOAD)\r
439 SBR = CES; /* in load mode, SBR follows the console switches */\r
440\r
441 if (IAR != shown_iar)\r
442 {shown_iar = IAR; RedrawRegion(hConsoleWnd, 75, 8, 364, 32);} /* lamps: don't bother erasing bkgnd */\r
443 if (SAR != shown_sar)\r
444 {shown_sar = SAR; RedrawRegion(hConsoleWnd, 75, 42, 364, 65);}\r
445 if (ARF != shown_arf)\r
446 {shown_arf = ARF; RedrawRegion(hConsoleWnd, 75, 114, 364, 136);}\r
447 if (ACC != shown_acc)\r
448 {shown_acc = ACC; RedrawRegion(hConsoleWnd, 75, 141, 364, 164);}\r
449 if (EXT != shown_ext)\r
450 {shown_ext = EXT; RedrawRegion(hConsoleWnd, 75, 174, 364, 197);}\r
451 if (SBR != shown_sbr)\r
452 {shown_sbr = SBR; RedrawRegion(hConsoleWnd, 75, 77, 364, 97);}\r
453 if (OP != shown_op) \r
454 {shown_op = OP; RedrawRegion(hConsoleWnd, 501, 8, 595, 32);}\r
455 if (TAG != shown_tag)\r
456 {shown_tag = TAG; RedrawRegion(hConsoleWnd, 501, 77, 595, 97);}\r
457\r
458 if (int_lamps != shown_irq)\r
459 {shown_irq = int_lamps; RedrawRegion(hConsoleWnd, 501, 108, 595, 130);}\r
460\r
461 if (CCC != shown_ccc)\r
462 {shown_ccc = CCC; RedrawRegion(hConsoleWnd, 501, 141, 595, 164);}\r
463 if (CND != shown_cnd)\r
464 {shown_cnd = CND; RedrawRegion(hConsoleWnd, 501, 174, 595, 197);}\r
465 if ((wait_state|wait_lamp) != shown_wait)\r
466 {shown_wait= (wait_state|wait_lamp); RedrawRegion(hConsoleWnd, 380, 77, 414, 97);}\r
467 if (CES != shown_ces)\r
468 {shown_ces = CES; RepaintRegion(hConsoleWnd, TOGGLES_X-7, 230, TOGGLES_X+360, 275);} /* console entry sw: do erase bkgnd */\r
469 if (RUNMODE != shown_runmode)\r
470 {shown_runmode = RUNMODE;RepaintRegion(hConsoleWnd, RUNSWITCH_X-50, RUNSWITCH_Y-50, RUNSWITCH_X+50, RUNSWITCH_Y+50);}\r
471\r
472 int_lamps = 0;\r
473\r
474 /* this loop works with lamp buttons that are calculated on-the-fly only */\r
475 for (i = 0; i < NBUTTONS; i++) {\r
476 if (btn[i].pushable)\r
477 continue;\r
478\r
479 switch (i) {\r
480 case IDC_RUN:\r
481 state = hFlashTimer || (running && ! wait_state);\r
482 break;\r
483\r
484/* this button is always off\r
485 case IDC_PARITY_CHECK\r
486*/\r
487\r
488/* these buttons are enabled/disabled directly\r
489 case IDC_POWER_ON:\r
490 case IDC_FILE_READY:\r
491 case IDC_FORMS_CHECK:\r
492 case IDC_KEYBOARD_SELECT:\r
493 case IDC_DISK_UNLOCK:\r
494*/\r
495 default:\r
496 continue;\r
497 }\r
498\r
499 if (state != btn[i].state) { /* state has changed */\r
500 EnableWindow(btn[i].hBtn, state);\r
501 btn[i].state = state;\r
502 }\r
503 }\r
504\r
505 if (force) { /* if force flag is set, update text region */\r
506 SetRect(&xin, TXTBOX_X, TXTBOX_Y, TXTBOX_X+TXTBOX_WIDTH, TXTBOX_BOTTOM+2*TXTBOX_HEIGHT);\r
507 InvalidateRect(hConsoleWnd, &xin, TRUE);\r
508 }\r
509\r
510 state = ((cr_unit.flags & UNIT_ATT) == 0) ? STATE_1442_EMPTY :\r
511 (cr_unit.flags & UNIT_PHYSICAL) ? STATE_1442_HIDDEN :\r
512 (cr_unit.flags & UNIT_CR_EMPTY) ? STATE_1442_EOF : \r
513 cr_unit.pos ? STATE_1442_MIDDLE :\r
514 STATE_1442_FULL;\r
515\r
516 if (state != btn[IDC_1442].state) {\r
517 if (state == STATE_1442_HIDDEN)\r
518 ShowWindow(btn[IDC_1442].hBtn, SW_HIDE);\r
519 else {\r
520 if (btn[IDC_1442].state == STATE_1442_HIDDEN)\r
521 ShowWindow(btn[IDC_1442].hBtn, SW_SHOWNA);\r
522\r
523 SendMessage(btn[IDC_1442].hBtn, STM_SETIMAGE, IMAGE_BITMAP,\r
524 (LPARAM) (\r
525 (state == STATE_1442_FULL) ? hbm1442_full :\r
526 (state == STATE_1442_MIDDLE) ? hbm1442_middle : \r
527 (state == STATE_1442_EOF) ? hbm1442_eof :\r
528 hbm1442_empty));\r
529 }\r
530\r
531 btn[IDC_1442].state = state;\r
532 }\r
533\r
534 state = ((prt_unit.flags & UNIT_ATT) == 0) ? STATE_1132_EMPTY :\r
535 (prt_unit.flags & UNIT_PHYSICAL_PTR) ? STATE_1132_HIDDEN :\r
536 prt_unit.pos ? STATE_1132_FULL :\r
537 STATE_1132_EMPTY;\r
538\r
539 if (state != btn[IDC_1132].state) {\r
540 if (state == STATE_1132_HIDDEN)\r
541 ShowWindow(btn[IDC_1132].hBtn, SW_HIDE);\r
542 else {\r
543 if (btn[IDC_1132].state == STATE_1132_HIDDEN)\r
544 ShowWindow(btn[IDC_1132].hBtn, SW_SHOWNA);\r
545\r
546 SendMessage(btn[IDC_1132].hBtn, STM_SETIMAGE, IMAGE_BITMAP,\r
547 (LPARAM) (\r
548 (state == STATE_1132_FULL) ? hbm1132_full : hbm1132_empty));\r
549 }\r
550\r
551 btn[IDC_1132].state = state;\r
552 }\r
553\r
554 in_here = FALSE;\r
555}\r
556\r
557WNDPROC oldButtonProc = NULL;\r
558\r
559/* ------------------------------------------------------------------------ \r
560 * ------------------------------------------------------------------------ */\r
561\r
562LRESULT CALLBACK ButtonProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
563{\r
564 int i;\r
565\r
566 i = GetWindowLong(hWnd, GWL_ID);\r
567\r
568 if (! btn[i].pushable) {\r
569 if (uMsg == WM_LBUTTONDOWN || uMsg == WM_LBUTTONUP || uMsg == WM_LBUTTONDBLCLK)\r
570 return 0;\r
571\r
572 if (uMsg == WM_CHAR)\r
573 if ((TCHAR) wParam == ' ')\r
574 return 0;\r
575 }\r
576\r
577 return CallWindowProc(oldButtonProc, hWnd, uMsg, wParam, lParam);\r
578}\r
579\r
580/* ------------------------------------------------------------------------ \r
581 * ------------------------------------------------------------------------ */\r
582\r
583static int occurs (char *txt, char ch)\r
584{\r
585 int count = 0;\r
586\r
587 while (*txt)\r
588 if (*txt++ == ch)\r
589 count++;\r
590\r
591 return count;\r
592}\r
593\r
594/* ------------------------------------------------------------------------ \r
595 * turns out to get properly colored buttons you have to paint them yourself. Sheesh.\r
596 * On the plus side, this lets do a better job of aligning the button text than\r
597 * the button would by itself.\r
598 * ------------------------------------------------------------------------ */\r
599\r
600void PaintButton (LPDRAWITEMSTRUCT dis)\r
601{\r
602 int i = dis->CtlID, nc, nlines, x, y, dy;\r
603 BOOL down = dis->itemState & ODS_SELECTED;\r
604 HPEN hOldPen;\r
605 HFONT hOldFont;\r
606 UINT oldAlign;\r
607 COLORREF oldBk;\r
608 char *txt, *tstart;\r
609\r
610 if (! BETWEEN(i, 0, NBUTTONS-1))\r
611 return;\r
612\r
613 if (! btn[i].subclassed)\r
614 return;\r
615\r
616 FillRect(dis->hDC, &dis->rcItem, ((btn[i].pushable || power) && IsWindowEnabled(btn[i].hBtn)) ? btn[i].hbrLit : btn[i].hbrDark);\r
617\r
618 if (! btn[i].pushable) {\r
619 hOldPen = SelectObject(dis->hDC, hBlackPen);\r
620 MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.top, NULL);\r
621 LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top);\r
622 LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.bottom-1);\r
623 LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-1);\r
624 LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.top);\r
625 }\r
626 else if (down) {\r
627 /* do the three-D thing */\r
628 hOldPen = SelectObject(dis->hDC, hDkGreyPen);\r
629 MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-2, NULL);\r
630 LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.top);\r
631 LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top);\r
632\r
633 SelectObject(dis->hDC, hWhitePen);\r
634 MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-1, NULL);\r
635 LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.bottom-1);\r
636 LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top);\r
637\r
638 SelectObject(dis->hDC, hGreyPen);\r
639 MoveToEx(dis->hDC, dis->rcItem.left+1, dis->rcItem.bottom-3, NULL);\r
640 LineTo(dis->hDC, dis->rcItem.left+1, dis->rcItem.top+1);\r
641 LineTo(dis->hDC, dis->rcItem.right-3, dis->rcItem.top+1);\r
642 }\r
643 else {\r
644 hOldPen = SelectObject(dis->hDC, hWhitePen);\r
645 MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-2, NULL);\r
646 LineTo(dis->hDC, dis->rcItem.left, dis->rcItem.top);\r
647 LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top);\r
648\r
649 SelectObject(dis->hDC, hDkGreyPen);\r
650 MoveToEx(dis->hDC, dis->rcItem.left, dis->rcItem.bottom-1, NULL);\r
651 LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.bottom-1);\r
652 LineTo(dis->hDC, dis->rcItem.right-1, dis->rcItem.top);\r
653\r
654 SelectObject(dis->hDC, hGreyPen);\r
655 MoveToEx(dis->hDC, dis->rcItem.left+1, dis->rcItem.bottom-2, NULL);\r
656 LineTo(dis->hDC, dis->rcItem.right-2, dis->rcItem.bottom-2);\r
657 LineTo(dis->hDC, dis->rcItem.right-2, dis->rcItem.top+1);\r
658 }\r
659\r
660 SelectObject(dis->hDC, hOldPen);\r
661\r
662 hOldFont = SelectObject(dis->hDC, hBtnFont);\r
663 oldAlign = SetTextAlign(dis->hDC, TA_CENTER|TA_TOP);\r
664 oldBk = SetBkMode(dis->hDC, TRANSPARENT);\r
665\r
666 txt = btn[i].txt;\r
667 nlines = occurs(txt, '\n')+1;\r
668 x = (dis->rcItem.left + dis->rcItem.right) / 2;\r
669 y = (dis->rcItem.top + dis->rcItem.bottom) / 2;\r
670\r
671 dy = 14;\r
672 y = y - (nlines*dy)/2;\r
673\r
674 if (down) {\r
675 x += 1;\r
676 y += 1;\r
677 }\r
678\r
679 for (;;) {\r
680 for (nc = 0, tstart = txt; *txt && *txt != '\n'; txt++, nc++)\r
681 ;\r
682\r
683 TextOut(dis->hDC, x, y, tstart, nc);\r
684\r
685 if (*txt == '\0')\r
686 break;\r
687\r
688 txt++;\r
689 y += dy;\r
690 }\r
691\r
692 SetTextAlign(dis->hDC, oldAlign);\r
693 SetBkMode(dis->hDC, oldBk);\r
694 SelectObject(dis->hDC, hOldFont);\r
695}\r
696 \r
697/* ------------------------------------------------------------------------ \r
698 * ------------------------------------------------------------------------ */\r
699\r
700HWND CreateSubclassedButton (HWND hwParent, int i)\r
701{\r
702 HWND hBtn;\r
703 int x, y;\r
704 int r, g, b;\r
705\r
706 y = bmht - (4*BUTTON_HEIGHT) + BUTTON_HEIGHT * btn[i].y;\r
707 x = (btn[i].x < 2) ? (btn[i].x*BUTTON_WIDTH) : (598 - (4-btn[i].x)*BUTTON_WIDTH);\r
708\r
709 if ((hBtn = CreateWindow("BUTTON", btn[i].txt, WS_CHILD|WS_VISIBLE|BS_CENTER|BS_MULTILINE|BS_OWNERDRAW,\r
710 x, y, BUTTON_WIDTH, BUTTON_HEIGHT, hwParent, (HMENU) i, hInstance, NULL)) == NULL)\r
711 return NULL;\r
712\r
713 btn[i].hBtn = hBtn;\r
714\r
715 if (oldButtonProc == NULL)\r
716 oldButtonProc = (WNDPROC) GetWindowLong(hBtn, GWL_WNDPROC);\r
717\r
718 btn[i].hbrLit = CreateSolidBrush(btn[i].clr);\r
719\r
720 if (! btn[i].pushable) {\r
721 r = GetRValue(btn[i].clr) / 4;\r
722 g = GetGValue(btn[i].clr) / 4;\r
723 b = GetBValue(btn[i].clr) / 4;\r
724\r
725 btn[i].hbrDark = CreateSolidBrush(RGB(r,g,b));\r
726 EnableWindow(hBtn, FALSE);\r
727 }\r
728\r
729 SetWindowLong(hBtn, GWL_WNDPROC, (LONG) ButtonProc);\r
730 return hBtn;\r
731}\r
732\r
733/* ------------------------------------------------------------------------ \r
734 * Pump - thread that takes care of the console window. It has to be a separate thread so that it gets\r
735 * execution time even when the simulator is compute-bound or IO-blocked. This routine creates the window\r
736 * and runs a standard Windows message pump. The window function does the actual display work.\r
737 * ------------------------------------------------------------------------ */\r
738\r
739static DWORD WINAPI Pump (LPVOID arg)\r
740{\r
741 MSG msg;\r
742 int wx, wy, i;\r
743 RECT r, ra;\r
744 BITMAP bm;\r
745 WNDCLASS cd;\r
746 HDC hDC;\r
747 HWND hActWnd;\r
748\r
749 hActWnd = GetForegroundWindow();\r
750\r
751 if (! class_defined) { /* register Window class */\r
752 hInstance = GetModuleHandle(NULL);\r
753\r
754 memset(&cd, 0, sizeof(cd));\r
755 cd.style = CS_NOCLOSE;\r
756 cd.lpfnWndProc = ConsoleWndProc;\r
757 cd.cbClsExtra = 0;\r
758 cd.cbWndExtra = 0;\r
759 cd.hInstance = hInstance;\r
760 cd.hIcon = NULL;\r
761 cd.hCursor = hcArrow;\r
762 cd.hbrBackground = NULL;\r
763 cd.lpszMenuName = NULL;\r
764 cd.lpszClassName = szConsoleClassName;\r
765\r
766 if (! RegisterClass(&cd)) {\r
767 PumpID = 0;\r
768 return 0;\r
769 }\r
770\r
771 class_defined = TRUE;\r
772 }\r
773\r
774 hbWhite = GetStockObject(WHITE_BRUSH); /* create or fetch useful GDI objects */\r
775 hbBlack = GetStockObject(BLACK_BRUSH); /* create or fetch useful GDI objects */\r
776 hbGray = GetStockObject(GRAY_BRUSH);\r
777 hSwitchPen = CreatePen(PS_SOLID, 5, RGB(255,255,255));\r
778\r
779 hWhitePen = GetStockObject(WHITE_PEN);\r
780 hBlackPen = GetStockObject(BLACK_PEN);\r
781 hLtGreyPen = CreatePen(PS_SOLID, 1, RGB(190,190,190));\r
782 hGreyPen = CreatePen(PS_SOLID, 1, RGB(128,128,128));\r
783 hDkGreyPen = CreatePen(PS_SOLID, 1, RGB(64,64,64));\r
784\r
785 hcArrow = LoadCursor(NULL, IDC_ARROW);\r
786#ifdef IDC_HAND\r
787 hcHand = LoadCursor(NULL, IDC_HAND); /* use stock object provided by Windows */\r
788 if (hcHand == NULL)\r
789 hcHand = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_MYHAND));\r
790#else\r
791 hcHand = LoadCursor(hInstance, MAKEINTRESOURCE(IDC_MYHAND));\r
792#endif\r
793\r
794 if (hBitmap == NULL)\r
795 hBitmap = LoadBitmap(hInstance, MAKEINTRESOURCE(IDB_CONSOLE));\r
796 if (hbLampOut == NULL)\r
797 hbLampOut = CreateSolidBrush(RGB(50,50,50));\r
798 if (hFont == NULL)\r
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");\r
800 if (hBtnFont == NULL)\r
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");\r
802 if (hTinyFont == NULL)\r
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");\r
804\r
805 if (hConsoleWnd == NULL) { /* create window */\r
806 if ((hConsoleWnd = CreateWindow(szConsoleClassName, "IBM 1130", WS_OVERLAPPED|WS_CLIPCHILDREN, 0, 0, 200, 200, NULL, NULL, hInstance, NULL)) == NULL) {\r
807 PumpID = 0;\r
808 return 0;\r
809 }\r
810\r
811 DragAcceptFiles(hConsoleWnd, TRUE); /* let it accept dragged files (scripts) */\r
812 }\r
813\r
814 GetObject(hBitmap, sizeof(bm), &bm); /* get bitmap size */\r
815 bmwid = bm.bmWidth;\r
816 bmht = bm.bmHeight;\r
817\r
818 for (i = 0; i < NBUTTONS; i++) {\r
819 if (! btn[i].subclassed)\r
820 continue;\r
821\r
822 CreateSubclassedButton(hConsoleWnd, i);\r
823 if (! btn[i].pushable)\r
824 EnableWindow(btn[i].hBtn, btn[i].state);\r
825 }\r
826\r
827/* This isn't needed anymore, now that we have the big printer icon -- it acts like a button now\r
828 * i = IDC_TEAR;\r
829 * btn[i].hBtn = CreateWindow("BUTTON", btn[i].txt, WS_CHILD|WS_VISIBLE|BS_CENTER,\r
830 * btn[i].x, btn[i].y, btn[i].wx, btn[i].wy, hConsoleWnd, (HMENU) i, hInstance, NULL);\r
831 *\r
832 * SendMessage(btn[i].hBtn, WM_SETFONT, (WPARAM) hTinyFont, TRUE);\r
833 */\r
834\r
835 hbm1442_full = LoadBitmap(hInstance, "FULL_1442");\r
836 hbm1442_empty = LoadBitmap(hInstance, "EMPTY_1442");\r
837 hbm1442_eof = LoadBitmap(hInstance, "EOF_1442");\r
838 hbm1442_middle = LoadBitmap(hInstance, "MIDDLE_1442");\r
839 hbm1132_full = LoadBitmap(hInstance, "FULL_1132");\r
840 hbm1132_empty = LoadBitmap(hInstance, "EMPTY_1132");\r
841\r
842 i = IDC_1442;\r
843\r
844 btn[i].hBtn = CreateWindow("STATIC", btn[i].txt, WS_CHILD|WS_VISIBLE|SS_BITMAP|SS_SUNKEN|WS_BORDER|SS_REALSIZEIMAGE|SS_NOTIFY,\r
845 btn[i].x, btn[i].y, btn[i].wx, btn[i].wy, hConsoleWnd, (HMENU) i, hInstance, NULL);\r
846 btn[i].state = STATE_1442_EMPTY;\r
847\r
848 wx = SendMessage(btn[i].hBtn, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hbm1442_empty);\r
849\r
850 i = IDC_1132;\r
851\r
852 btn[i].hBtn = CreateWindow("STATIC", btn[i].txt, WS_CHILD|WS_VISIBLE|SS_BITMAP|SS_SUNKEN|WS_BORDER|SS_REALSIZEIMAGE|SS_NOTIFY,\r
853 btn[i].x, btn[i].y, btn[i].wx, btn[i].wy, hConsoleWnd, (HMENU) i, hInstance, NULL);\r
854 btn[i].state = FALSE;\r
855\r
856 wx = SendMessage(btn[i].hBtn, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM) hbm1132_empty);\r
857\r
858 GetWindowRect(hConsoleWnd, &r); /* get window size as created */\r
859 wx = r.right - r.left + 1;\r
860 wy = r.bottom - r.top + 1;\r
861\r
862 if (hCDC == NULL) { /* get a memory DC and select the bitmap into ti */\r
863 hDC = GetDC(hConsoleWnd);\r
864 hCDC = CreateCompatibleDC(hDC);\r
865 SelectObject(hCDC, hBitmap);\r
866 ReleaseDC(hConsoleWnd, hDC);\r
867 }\r
868\r
869 GetClientRect(hConsoleWnd, &r);\r
870 wx = (wx - r.right - 1) + bmwid; /* compute new desired size based on how client area came out */\r
871 wy = (wy - r.bottom - 1) + bmht;\r
872 MoveWindow(hConsoleWnd, 0, 0, wx, wy, FALSE); /* resize window */\r
873\r
874 ShowWindow(hConsoleWnd, SW_SHOWNOACTIVATE); /* display it */\r
875 UpdateWindow(hConsoleWnd);\r
876\r
877 if (hActWnd != NULL) { /* bring console (sim) window back to top */\r
878 GetWindowRect(hConsoleWnd, &r);\r
879 ShowWindow(hActWnd, SW_NORMAL); /* and move it just below the display window */\r
880 SetWindowPos(hActWnd, HWND_TOP, 0, r.bottom, 0, 0, SWP_NOSIZE);\r
881 GetWindowRect(hActWnd, &ra);\r
882 if (ra.bottom >= GetSystemMetrics(SM_CYSCREEN)) { /* resize if it goes of bottom of screen */\r
883 ra.bottom = GetSystemMetrics(SM_CYSCREEN) - 1;\r
884 SetWindowPos(hActWnd, 0, 0, 0, ra.right-ra.left+1, ra.bottom-ra.top+1, SWP_NOZORDER|SWP_NOMOVE);\r
885 }\r
886 }\r
887\r
888 if (running) /* if simulator is already running, start update timer */\r
889 gui_run(TRUE);\r
890\r
891 while (GetMessage(&msg, hConsoleWnd, 0, 0)) { /* message pump - this basically loops forevermore */\r
892 TranslateMessage(&msg);\r
893 DispatchMessage(&msg);\r
894 }\r
895\r
896 if (hConsoleWnd != NULL) { \r
897 DragAcceptFiles(hConsoleWnd, FALSE); /* unregister as drag/drop target */\r
898 DestroyWindow(hConsoleWnd); /* but if a quit message got posted, clean up */\r
899 hConsoleWnd = NULL;\r
900 }\r
901\r
902 PumpID = 0;\r
903 return 0;\r
904}\r
905\r
906/* ------------------------------------------------------------------------ \r
907 * DrawBits - starting at position (x,y), draw lamps for nbits bits of word 'bits', looking only at masked bits\r
908 * ------------------------------------------------------------------------ */\r
909\r
910static void DrawBits (HDC hDC, int x, int y, int bits, int nbits, int mask, char *syms)\r
911{\r
912 int i, b = 0x0001 << (nbits-1);\r
913\r
914 for (i = 0; i < nbits; i++, b >>= 1) {\r
915 if (mask & b) { /* select white or black lettering then write 2 chars */\r
916 SetTextColor(hDC, (b & bits && power) ? RGB(255,255,255) : RGB(0,0,0));\r
917 TextOut(hDC, x, y, syms, 2);\r
918 }\r
919 syms += 2; /* go to next symbol pair */\r
920\r
921 if (i < 10)\r
922 x += 15; /* step between lamps */\r
923 else\r
924 x += 19;\r
925\r
926 if (x < 500) {\r
927 if (b & 0x1110)\r
928 x += 10; /* step over nibble divisions on left side */\r
929 else if (b & 0x0001)\r
930 x += 9;\r
931 }\r
932 }\r
933}\r
934\r
935/* ------------------------------------------------------------------------ \r
936 * DrawToggles - display the console sense switches\r
937 * ------------------------------------------------------------------------ */\r
938\r
939\r
940static void DrawToggles (HDC hDC, int bits)\r
941{\r
942 int b, x;\r
943\r
944 for (b = 0x8000, x = TOGGLES_X; b != 0; b >>= 1) {\r
945 if (shown_ces & b) { /* up */\r
946 SelectObject(hDC, hbWhite);\r
947 Rectangle(hDC, x, 232, x+9, 240);\r
948 SelectObject(hDC, hbGray);\r
949 Rectangle(hDC, x, 239, x+9, 255);\r
950 }\r
951 else { /* down */\r
952 SelectObject(hDC, hbWhite);\r
953 Rectangle(hDC, x, 263, x+9, 271);\r
954 SelectObject(hDC, hbGray);\r
955 Rectangle(hDC, x, 248, x+9, 264);\r
956 }\r
957\r
958 x += (b & 0x1111) ? 31 : 21;\r
959 }\r
960}\r
961\r
962/* ------------------------------------------------------------------------ \r
963 * DrawRunmode - draw the run mode rotary switch's little tip\r
964 * ------------------------------------------------------------------------ */\r
965\r
966void DrawRunmode (HDC hDC, int mode)\r
967{\r
968 double angle = (mode*45. + 90.) * 3.1415926 / 180.; /* convert mode position to angle in radians */\r
969 double ca, sa; /* sine and cosine */\r
970 int x0, y0, x1, y1;\r
971 HPEN hOldPen;\r
972\r
973 ca = cos(angle);\r
974 sa = sin(angle);\r
975\r
976 x0 = RUNSWITCH_X + (int) (20.*ca + 0.5); /* inner radius */\r
977 y0 = RUNSWITCH_Y - (int) (20.*sa + 0.5);\r
978 x1 = RUNSWITCH_X + (int) (25.*ca + 0.5); /* outer radius */\r
979 y1 = RUNSWITCH_Y - (int) (25.*sa + 0.5);\r
980\r
981 hOldPen = SelectObject(hDC, hSwitchPen);\r
982\r
983 MoveToEx(hDC, x0, y0, NULL);\r
984 LineTo(hDC, x1, y1);\r
985\r
986 SelectObject(hDC, hOldPen);\r
987}\r
988\r
989/* ------------------------------------------------------------------------ \r
990 * HandleClick - handle mouse clicks on the console window. Now we just \r
991 * look at the console sense switches. Actual says this is a real click, rather\r
992 * than a mouse-region test. Return value TRUE means the cursor is over a hotspot.\r
993 * ------------------------------------------------------------------------ */\r
994\r
995static BOOL HandleClick (HWND hWnd, int xh, int yh, BOOL actual, BOOL rightclick)\r
996{\r
997 int b, x, r, ang, i;\r
998\r
999 for (b = 0x8000, x = TOGGLES_X; b != 0; b >>= 1) {\r
1000 if (BETWEEN(xh, x-3, x+8+3) && BETWEEN(yh, 230, 275)) {\r
1001 if (actual) {\r
1002 CES ^= b; /* a hit. Invert the bit and redisplay */\r
1003 update_gui(TRUE);\r
1004 }\r
1005 return TRUE;\r
1006 }\r
1007 x += (b & 0x1111) ? 31 : 21;\r
1008 }\r
1009\r
1010 if (BETWEEN(xh, RUNSWITCH_X-50, RUNSWITCH_X+50) && BETWEEN(yh, RUNSWITCH_Y-50, RUNSWITCH_Y+50)) { /* hit near rotary switch */\r
1011 ang = (int) (atan2(RUNSWITCH_X-xh, RUNSWITCH_Y-yh)*180./3.1415926); /* this does implicit 90 deg rotation by the way */\r
1012 r = (int) sqrt((xh-RUNSWITCH_X)*(xh-RUNSWITCH_X)+(yh-RUNSWITCH_Y)*(yh-RUNSWITCH_Y));\r
1013 if (r > 12) {\r
1014 for (i = MODE_LOAD; i <= MODE_INT_RUN; i++) {\r
1015 if (BETWEEN(ang, i*45-12, i*45+12)) {\r
1016 if (actual) {\r
1017 RUNMODE = i;\r
1018 update_gui(TRUE);\r
1019 }\r
1020 return TRUE;\r
1021 }\r
1022 }\r
1023 \r
1024 }\r
1025 }\r
1026\r
1027 return FALSE;\r
1028}\r
1029\r
1030/* ------------------------------------------------------------------------ \r
1031 * DrawConsole - refresh the console display. (This routine could be sped up by intersecting\r
1032 * the various components' bounding rectangles with the repaint rectangle. The bounding rects\r
1033 * could be put into an array and used both here and in the refresh routine).\r
1034 *\r
1035 * RedrawRegion -> force repaint w/o background redraw. used for lamps which are drawn in the same place in either state\r
1036 * RepaintRegion-> repaint with background redraw. Used for toggles which change position.\r
1037 * ------------------------------------------------------------------------ */\r
1038\r
1039static void DrawConsole (HDC hDC, PAINTSTRUCT *ps)\r
1040{\r
1041 static char digits[] = " 0 1 2 3 4 5 6 7 8 9101112131415";\r
1042 static char cccs[] = "3216 8 4 2 1";\r
1043 static char cnds[] = " C V";\r
1044 static char waits[] = " W";\r
1045 HFONT hOldFont, hOldBrush;\r
1046 RECT xout, xin;\r
1047 int i, n;\r
1048 DEVICE *dptr;\r
1049 UNIT *uptr;\r
1050 t_bool enab;\r
1051 char nametemp[50], *dispname;\r
1052\r
1053 hOldFont = SelectObject(hDC, hFont); /* use that tiny font */\r
1054 hOldBrush = SelectObject(hDC, hbWhite);\r
1055\r
1056 SetBkMode(hDC, TRANSPARENT); /* overlay letters w/o changing background */\r
1057\r
1058 DrawBits(hDC, 76, 15, shown_iar, 16, mem_mask, digits); /* register holds only 15 bits */\r
1059 DrawBits(hDC, 76, 48, shown_sar, 16, mem_mask, digits); /* but let's display only used bits */\r
1060 DrawBits(hDC, 76, 81, shown_sbr, 16, 0xFFFF, digits);\r
1061 DrawBits(hDC, 76, 114, shown_arf, 16, 0xFFFF, digits);\r
1062 DrawBits(hDC, 76, 147, shown_acc, 16, 0xFFFF, digits);\r
1063 DrawBits(hDC, 76, 180, shown_ext, 16, 0xFFFF, digits);\r
1064\r
1065 DrawBits(hDC, 506, 15, shown_op, 5, 0x001F, digits);\r
1066 DrawBits(hDC, 506, 81, shown_tag, 4, 0x0007, digits);\r
1067 DrawBits(hDC, 506, 114, shown_irq, 6, 0x003F, digits);\r
1068 DrawBits(hDC, 506, 147, shown_ccc, 6, 0x003F, cccs);\r
1069 DrawBits(hDC, 506, 180, shown_cnd, 2, 0x0003, cnds);\r
1070\r
1071 DrawBits(hDC, 390, 81, shown_wait?1:0,1, 0x0001, waits);\r
1072\r
1073 DrawToggles(hDC, shown_ces);\r
1074\r
1075 DrawRunmode(hDC, shown_runmode);\r
1076\r
1077 SelectObject(hDC, hOldFont);\r
1078 SelectObject(hDC, hOldBrush);\r
1079\r
1080 SetBkColor(hDC, RGB(0,0,0));\r
1081\r
1082 SetRect(&xin, TXTBOX_X, TXTBOX_Y, TXTBOX_X+TXTBOX_WIDTH, TXTBOX_BOTTOM+TXTBOX_HEIGHT);\r
1083 if (IntersectRect(&xout, &xin, &ps->rcPaint)) {\r
1084 hOldFont = SelectObject(hDC, hTinyFont);\r
1085\r
1086 for (i = 0; i < NTXTBOXES; i++) {\r
1087 enab = FALSE;\r
1088\r
1089 dptr = find_unit(txtbox[i].unitname, &uptr);\r
1090 if (dptr != NULL && uptr != NULL) {\r
1091 if (uptr->flags & UNIT_DIS) {\r
1092 SetTextColor(hDC, RGB(128,0,0));\r
1093 }\r
1094 else if (uptr->flags & UNIT_ATT) {\r
1095 SetTextColor(hDC, RGB(0,0,255));\r
1096 if ((n = strlen(uptr->filename)) > 30) {\r
1097 strcpy(nametemp, "...");\r
1098 strcpy(nametemp+3, uptr->filename+n-30);\r
1099 dispname = nametemp; \r
1100 }\r
1101 else\r
1102 dispname = uptr->filename;\r
1103\r
1104 TextOut(hDC, txtbox[i].x+25, txtbox[i].y+TXTBOX_HEIGHT, dispname, strlen(dispname));\r
1105 SetTextColor(hDC, RGB(255,255,255));\r
1106 enab = TRUE;\r
1107 }\r
1108 else {\r
1109 SetTextColor(hDC, RGB(128,128,128));\r
1110 }\r
1111 TextOut(hDC, txtbox[i].x, txtbox[i].y, txtbox[i].txt, strlen(txtbox[i].txt));\r
1112 }\r
1113\r
1114 if (txtbox[i].idctrl >= 0)\r
1115 EnableWindow(btn[txtbox[i].idctrl].hBtn, enab);\r
1116 }\r
1117\r
1118 SelectObject(hDC, hOldFont);\r
1119 }\r
1120}\r
1121\r
1122/* ------------------------------------------------------------------------ \r
1123 * Handles button presses. Remember that this occurs in the context of \r
1124 * the Pump thread, not the simulator thread.\r
1125 * ------------------------------------------------------------------------ */\r
1126\r
1127void flash_run (void) \r
1128{\r
1129 EnableWindow(btn[IDC_RUN].hBtn, TRUE); /* enable the run lamp */\r
1130\r
1131 if (hFlashTimer != 0)\r
1132 KillTimer(hConsoleWnd, FLASH_TIMER_ID); /* (re)schedule lamp update */\r
1133\r
1134 hFlashTimer = SetTimer(hConsoleWnd, FLASH_TIMER_ID, LAMPTIME, NULL);\r
1135}\r
1136\r
1137void gui_run (int running)\r
1138{\r
1139 if (running && hUpdateTimer == 0 && hConsoleWnd != NULL) {\r
1140 hUpdateTimer = SetTimer(hConsoleWnd, UPDATE_TIMER_ID, 1000/UPDATE_INTERVAL, NULL);\r
1141 }\r
1142 else if (hUpdateTimer != 0 && ! running) {\r
1143 KillTimer(hConsoleWnd, UPDATE_TIMER_ID);\r
1144 hUpdateTimer = 0;\r
1145 }\r
1146 flash_run(); /* keep run lamp active for a while after we stop running */\r
1147} \r
1148\r
1149void HandleCommand (HWND hWnd, WORD wNotify, WORD idCtl, HWND hwCtl)\r
1150{\r
1151 int i;\r
1152\r
1153 switch (idCtl) {\r
1154 case IDC_POWER: /* toggle system power */\r
1155 power = ! power;\r
1156 reset_all(0);\r
1157 if (running && ! power) { /* turning off */\r
1158 reason = STOP_POWER_OFF;\r
1159 /* wait for execution thread to exit */\r
1160/* this prevents message pump from running, which unfortunately locks up\r
1161 * the emulator thread when it calls gui_run(FALSE) which calls EnableWindow on the Run lamp\r
1162 * while (running)\r
1163 * Sleep(10);\r
1164 */ \r
1165 }\r
1166\r
1167 btn[IDC_POWER_ON].state = power;\r
1168 EnableWindow(btn[IDC_POWER_ON].hBtn, power);\r
1169\r
1170 for (i = 0; i < NBUTTONS; i++) /* repaint all of the lamps */\r
1171 if (! btn[i].pushable)\r
1172 InvalidateRect(btn[i].hBtn, NULL, TRUE);\r
1173\r
1174 break;\r
1175\r
1176 case IDC_PROGRAM_START: /* begin execution */\r
1177 if (! running) {\r
1178 switch (RUNMODE) {\r
1179 case MODE_INT_RUN:\r
1180 case MODE_RUN:\r
1181 case MODE_SI:\r
1182 stuff_cmd("cont");\r
1183 break;\r
1184\r
1185 case MODE_DISP: /* display core and advance IAR */\r
1186 ReadW(IAR);\r
1187 IAR = IAR+1;\r
1188 flash_run(); /* illuminate run lamp for .5 sec */\r
1189 break;\r
1190\r
1191 case MODE_LOAD: /* store to core and advance IAR */\r
1192 WriteW(IAR, CES);\r
1193 IAR = IAR+1;\r
1194 flash_run();\r
1195 break;\r
1196 }\r
1197 }\r
1198 break;\r
1199\r
1200 case IDC_PROGRAM_STOP:\r
1201 if (running) { /* potential race condition here */\r
1202 GUI_BEGIN_CRITICAL_SECTION\r
1203 SETBIT(con_dsw, CPU_DSW_PROGRAM_STOP);\r
1204 SETBIT(ILSW[5], ILSW_5_INT_RUN_PROGRAM_STOP);\r
1205 int_req |= INT_REQ_5; /* note: calc_ints() is not needed in this case */\r
1206 int_lamps |= INT_REQ_5;\r
1207 GUI_END_CRITICAL_SECTION\r
1208 }\r
1209 break;\r
1210\r
1211 case IDC_LOAD_IAR:\r
1212 if (! running) {\r
1213 IAR = CES & mem_mask; /* set IAR from console entry switches */\r
1214 }\r
1215 break;\r
1216\r
1217 case IDC_KEYBOARD: /* toggle between console/keyboard mode */\r
1218 break;\r
1219\r
1220 case IDC_IMM_STOP:\r
1221 if (running) {\r
1222 reason = STOP_IMMEDIATE; /* terminate execution without setting wait_mode */\r
1223 /* wait for execution thread to exit */\r
1224/* this prevents message pump from running, which unfortunately locks up\r
1225 * the emulator thread when it calls gui_run(FALSE) which calls EnableWindow on the Run lamp\r
1226 * while (running)\r
1227 * Sleep(10); \r
1228 */\r
1229 }\r
1230 break;\r
1231\r
1232 case IDC_RESET:\r
1233 if (! running) { /* check-reset is disabled while running */\r
1234 reset_all(0);\r
1235 forms_check(0); /* clear forms-check status */\r
1236 print_check(0);\r
1237 }\r
1238 break;\r
1239\r
1240 case IDC_PROGRAM_LOAD:\r
1241 if (! running) { /* if card reader is attached to a file, do cold start read of one card */\r
1242 IAR = 0; /* reset IAR */\r
1243#ifdef PROGRAM_LOAD_STARTS_CPU\r
1244 stuff_cmd("boot cr");\r
1245#else\r
1246 if (cr_boot(0, NULL) != SCPE_OK) /* load boot card */\r
1247 remark_cmd("IPL failed");\r
1248#endif\r
1249 }\r
1250 break;\r
1251\r
1252 case IDC_TEAR: /* "tear off printer output" */\r
1253 case IDC_1132: /* do same if they click on the printer icon */\r
1254 if (btn[IDC_1132].state && (wNotify == STN_CLICKED || wNotify == STN_DBLCLK))\r
1255 tear_printer();\r
1256 break;\r
1257\r
1258 case IDC_1442:\r
1259 if (btn[IDC_1442].state == STATE_1442_FULL || wNotify == STN_DBLCLK)\r
1260 stuff_cmd("detach cr");\r
1261 else if (btn[IDC_1442].state != STATE_1442_EMPTY && wNotify == STN_CLICKED) {\r
1262 cr_rewind();\r
1263 update_gui(TRUE);\r
1264 }\r
1265 break;\r
1266 }\r
1267 \r
1268 update_gui(FALSE);\r
1269}\r
1270\r
1271/* ------------------------------------------------------------------------ \r
1272 * ConsoleWndProc - window process for the console display\r
1273 * ------------------------------------------------------------------------ */\r
1274\r
1275LRESULT CALLBACK ConsoleWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)\r
1276{\r
1277 HDC hDC;\r
1278 PAINTSTRUCT ps;\r
1279 POINT p;\r
1280 RECT clip, xsect, rbmp;\r
1281 int i;\r
1282\r
1283 switch (uMsg) {\r
1284 case WM_CLOSE:\r
1285 DestroyWindow(hWnd);\r
1286 break;\r
1287\r
1288 case WM_DESTROY:\r
1289 gui_run(FALSE);\r
1290 hConsoleWnd = NULL;\r
1291 break;\r
1292\r
1293 case WM_ERASEBKGND:\r
1294 hDC = (HDC) wParam;\r
1295 GetClipBox(hDC, &clip);\r
1296 SetRect(&rbmp, 0, 0, bmwid, bmht);\r
1297 if (IntersectRect(&xsect, &clip, &rbmp))\r
1298 BitBlt(hDC, xsect.left, xsect.top, xsect.right-xsect.left+1, xsect.bottom-xsect.top+1, hCDC, xsect.left, xsect.top, SRCCOPY);\r
1299 return TRUE; /* let Paint do this so we know what the update region is (ps.rcPaint) */\r
1300\r
1301 case WM_PAINT:\r
1302 hDC = BeginPaint(hWnd, &ps);\r
1303 DrawConsole(hDC, &ps);\r
1304 EndPaint(hWnd, &ps);\r
1305 break;\r
1306\r
1307 case WM_COMMAND: /* button click */\r
1308 HandleCommand(hWnd, HIWORD(wParam), LOWORD(wParam), (HWND) lParam);\r
1309 break;\r
1310\r
1311 case WM_CTLCOLOREDIT: /* text color for edit controls */\r
1312 SetBkColor((HDC) wParam, RGB(0,0,0));\r
1313 SetTextColor((HDC) wParam, RGB(255,255,255));\r
1314 break;\r
1315\r
1316 case WM_DRAWITEM:\r
1317 PaintButton((LPDRAWITEMSTRUCT) lParam);\r
1318 break;\r
1319\r
1320 case WM_SETCURSOR:\r
1321 GetCursorPos(&p);\r
1322 ScreenToClient(hWnd, &p);\r
1323 SetCursor(HandleClick(hWnd, p.x, p.y, FALSE, FALSE) ? hcHand : hcArrow);\r
1324 return TRUE;\r
1325\r
1326 case WM_LBUTTONDOWN:\r
1327 HandleClick(hWnd, LOWORD(lParam), HIWORD(lParam), TRUE, FALSE);\r
1328 break;\r
1329\r
1330 case WM_RBUTTONDOWN:\r
1331 HandleClick(hWnd, LOWORD(lParam), HIWORD(lParam), TRUE, TRUE);\r
1332 break;\r
1333\r
1334 case WM_CTLCOLORBTN:\r
1335 i = GetWindowLong((HWND) lParam, GWL_ID);\r
1336 if (BETWEEN(i, 0, NBUTTONS-1))\r
1337 return (LRESULT) (power && IsWindowEnabled((HWND) lParam) ? btn[i].hbrLit : btn[i].hbrDark);\r
1338\r
1339 case WM_TIMER:\r
1340 if (wParam == FLASH_TIMER_ID && hFlashTimer != 0) {\r
1341 KillTimer(hWnd, FLASH_TIMER_ID);\r
1342 hFlashTimer = 0;\r
1343 }\r
1344 update_gui(FALSE);\r
1345 break;\r
1346\r
1347 case WM_DROPFILES:\r
1348 accept_dropped_file((HANDLE) wParam); /* console window - dragged file is a script or card deck */\r
1349 break;\r
1350\r
1351 default:\r
1352 return DefWindowProc(hWnd, uMsg, wParam, lParam);\r
1353 }\r
1354\r
1355 return 0;\r
1356}\r
1357\r
1358enum {PRINTER_OK = 0, FORMS_CHECK = 1, PRINT_CHECK = 2, BOTH_CHECK = 3} printerstatus = PRINTER_OK;\r
1359\r
1360void forms_check (int set)\r
1361{\r
1362 COLORREF oldcolor = btn[IDC_FORMS_CHECK].clr;\r
1363\r
1364 if (set)\r
1365 SETBIT(printerstatus, FORMS_CHECK);\r
1366 else\r
1367 CLRBIT(printerstatus, FORMS_CHECK);\r
1368\r
1369 btn[IDC_FORMS_CHECK].clr = (printerstatus & PRINT_CHECK) ? RGB(255,0,0) : RGB(255,255,0);\r
1370\r
1371 btn[IDC_FORMS_CHECK].state = printerstatus;\r
1372\r
1373 if (btn[IDC_FORMS_CHECK].hBtn != NULL) {\r
1374 EnableWindow(btn[IDC_FORMS_CHECK].hBtn, printerstatus);\r
1375\r
1376 if (btn[IDC_FORMS_CHECK].clr != oldcolor)\r
1377 InvalidateRect(btn[IDC_FORMS_CHECK].hBtn, NULL, TRUE); /* change color in any case */\r
1378 }\r
1379}\r
1380\r
1381void print_check (int set)\r
1382{\r
1383 COLORREF oldcolor = btn[IDC_FORMS_CHECK].clr;\r
1384\r
1385 if (set)\r
1386 SETBIT(printerstatus, PRINT_CHECK);\r
1387 else\r
1388 CLRBIT(printerstatus, PRINT_CHECK);\r
1389\r
1390 btn[IDC_FORMS_CHECK].clr = (printerstatus & PRINT_CHECK) ? RGB(255,0,0) : RGB(255,255,0);\r
1391\r
1392 btn[IDC_FORMS_CHECK].state = printerstatus;\r
1393\r
1394 if (btn[IDC_FORMS_CHECK].hBtn != NULL) {\r
1395 EnableWindow(btn[IDC_FORMS_CHECK].hBtn, printerstatus);\r
1396\r
1397 if (btn[IDC_FORMS_CHECK].clr != oldcolor)\r
1398 InvalidateRect(btn[IDC_FORMS_CHECK].hBtn, NULL, TRUE); /* change color in any case */\r
1399 }\r
1400}\r
1401\r
1402void keyboard_selected (int select)\r
1403{\r
1404 btn[IDC_KEYBOARD_SELECT].state = select;\r
1405\r
1406 if (btn[IDC_KEYBOARD_SELECT].hBtn != NULL)\r
1407 EnableWindow(btn[IDC_KEYBOARD_SELECT].hBtn, select);\r
1408}\r
1409\r
1410void disk_ready (int ready)\r
1411{\r
1412 btn[IDC_FILE_READY].state = ready;\r
1413\r
1414 if (btn[IDC_FILE_READY].hBtn != NULL)\r
1415 EnableWindow(btn[IDC_FILE_READY].hBtn, ready);\r
1416}\r
1417\r
1418void disk_unlocked (int unlocked)\r
1419{\r
1420 btn[IDC_DISK_UNLOCK].state = unlocked;\r
1421\r
1422 if (btn[IDC_DISK_UNLOCK].hBtn != NULL)\r
1423 EnableWindow(btn[IDC_DISK_UNLOCK].hBtn, unlocked);\r
1424}\r
1425\r
1426static void accept_dropped_file (HANDLE hDrop)\r
1427{\r
1428 int nfiles;\r
1429 char fname[MAX_PATH], cmd[MAX_PATH+50], *deckfile;\r
1430 BOOL cardreader;\r
1431 POINT pt;\r
1432 HWND hWndDrop;\r
1433\r
1434 nfiles = DragQueryFile(hDrop, 0xFFFFFFFF, NULL, 0); /* get file count, */\r
1435 DragQueryFile(hDrop, 0, fname, sizeof(fname)); /* get first filename */\r
1436 DragQueryPoint(hDrop, &pt); /* get location of drop */\r
1437 DragFinish(hDrop);\r
1438\r
1439 if (nfiles <= 0) /* hmm, this seems unlikely to occur, but better check */\r
1440 return;\r
1441\r
1442 if (running) { /* can only accept a drop while processor is stopped */\r
1443 MessageBeep(0);\r
1444 return;\r
1445 }\r
1446\r
1447 if ((hWndDrop = ChildWindowFromPoint(hConsoleWnd, pt)) == btn[IDC_1442].hBtn)\r
1448 cardreader = TRUE; /* file was dropped onto 1442 card reader */\r
1449 else if (hWndDrop == NULL || hWndDrop == hConsoleWnd)\r
1450 cardreader = FALSE; /* file was dropped onto console window, not a button */\r
1451 else {\r
1452 MessageBeep(0); /* file was dropped onto another button */\r
1453 return;\r
1454 }\r
1455\r
1456 if (nfiles > 1) { /* oops, we wouldn't know what order to read them in */\r
1457 MessageBox(hConsoleWnd, "You may only drop one file at a time", "", MB_OK);\r
1458 return;\r
1459 }\r
1460\r
1461 /* if shift key is down, prepend @ to name (make it a deck file) */\r
1462 deckfile = ((GetKeyState(VK_SHIFT) & 0x8000) && cardreader) ? "@" : "";\r
1463\r
1464 sprintf(cmd, "%s \"%s%s\"", cardreader ? "attach cr" : "do", deckfile, fname);\r
1465 stuff_cmd(cmd);\r
1466}\r
1467\r
1468static void tear_printer (void)\r
1469{\r
1470 char cmd[MAX_PATH+100], filename[MAX_PATH];\r
1471\r
1472 if ((prt_unit.flags & UNIT_ATT) == 0)\r
1473 return;\r
1474\r
1475 strcpy(filename, prt_unit.filename); /* save current attached filename */\r
1476\r
1477 if (! stuff_and_wait("detach prt", 1000, 0)) /* detach it */\r
1478 return;\r
1479\r
1480 sprintf(cmd, "view \"%s\"", filename); /* spawn notepad to view it */\r
1481 if (! stuff_and_wait(cmd, 3000, 500))\r
1482 return;\r
1483\r
1484 remove(filename); /* delete the file */\r
1485\r
1486 sprintf(cmd, "attach prt \"%s\"", filename); /* reattach */\r
1487 stuff_cmd(cmd);\r
1488}\r
1489\r
1490#ifdef XXX\r
1491 if ((hBtn = CreateWindow("BUTTON", btn[i].txt, WS_CHILD|WS_VISIBLE|BS_CENTER|BS_MULTILINE|BS_OWNERDRAW,\r
1492 x, y, BUTTON_WIDTH, BUTTON_HEIGHT, hwParent, (HMENU) i, hInstance, NULL)) == NULL)\r
1493 return NULL;\r
1494\r
1495#endif\r
1496\r
1497CRITICAL_SECTION critsect;\r
1498\r
1499void begin_critical_section (void)\r
1500{\r
1501 static BOOL mustinit = TRUE;\r
1502\r
1503 if (mustinit) {\r
1504 InitializeCriticalSection(&critsect);\r
1505 mustinit = FALSE;\r
1506 }\r
1507\r
1508 EnterCriticalSection(&critsect);\r
1509}\r
1510\r
1511void end_critical_section (void)\r
1512{\r
1513 LeaveCriticalSection(&critsect);\r
1514}\r
1515\r
1516#ifndef MIN\r
1517# define MIN(a,b) (((a) <= (b)) ? (a) : (b))\r
1518#endif\r
1519\r
1520/* win32 - use a separate thread to read command lines so the GUI\r
1521 * can insert commands as well */\r
1522\r
1523static HANDLE hCmdThread = NULL;\r
1524static DWORD iCmdThreadID = 0;\r
1525static HANDLE hCmdReadEvent = NULL;\r
1526static HANDLE hCmdReadyEvent = NULL;\r
1527static BOOL scp_stuffed = FALSE, scp_reading = FALSE;\r
1528static char cmdbuffer[256];\r
1529\r
1530/* CmdThread - separate thread to read commands from stdin upon request */\r
1531\r
1532static DWORD WINAPI CmdThread (LPVOID arg)\r
1533{\r
1534 for (;;) {\r
1535 WaitForSingleObject(hCmdReadEvent, INFINITE); /* wait for request */\r
1536 read_line(cmdbuffer, sizeof(cmdbuffer), stdin); /* read one line */\r
1537 scp_stuffed = FALSE; /* say how we got it */\r
1538 scp_reading = FALSE;\r
1539 SetEvent(hCmdReadyEvent); /* notify main thread a line is ready */\r
1540 }\r
1541 return 0;\r
1542} \r
1543\r
1544char *read_cmdline (char *ptr, int size, FILE *stream)\r
1545{\r
1546 char *cptr;\r
1547\r
1548 if (hCmdThread == NULL) { /* set up command-reading thread */\r
1549 if ((hCmdReadEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL)\r
1550 scp_panic("Can't create command line read event");\r
1551\r
1552 if ((hCmdReadyEvent = CreateEvent(NULL, FALSE, FALSE, NULL)) == NULL)\r
1553 scp_panic("Can't create command line ready event");\r
1554 /* start up the command thread */\r
1555 if ((hCmdThread = CreateThread(NULL, 0, CmdThread, NULL, 0, &iCmdThreadID)) == NULL)\r
1556 scp_panic("Unable to create command line reading thread");\r
1557 }\r
1558\r
1559 scp_reading = TRUE;\r
1560\r
1561 SetEvent(hCmdReadEvent); /* let read thread get one line */\r
1562 WaitForSingleObject(hCmdReadyEvent, INFINITE); /* wait for read thread or GUI to respond */\r
1563 strncpy(ptr, cmdbuffer, MIN(size, sizeof(cmdbuffer))); /* copy line to caller's buffer */\r
1564\r
1565 for (cptr = ptr; isspace(*cptr); cptr++) /* absorb spaces */\r
1566 ;\r
1567\r
1568 if (scp_stuffed) { /* stuffed command needs to be echoed */\r
1569 printf("%s\n", cptr);\r
1570 if (sim_log) fprintf(sim_log, "%s\n", cptr);\r
1571 }\r
1572\r
1573 return cptr;\r
1574}\r
1575\r
1576/* stuff_cmd - force a command into the read_cmdline output buffer. Called asynchronously by GUI */\r
1577\r
1578void stuff_cmd (char *cmd)\r
1579{\r
1580 strcpy(cmdbuffer, cmd); /* save the string */\r
1581 scp_stuffed = TRUE; /* note where it came from */\r
1582 scp_reading = FALSE;\r
1583 ResetEvent(hCmdReadEvent); /* clear read request event */\r
1584 SetEvent(hCmdReadyEvent); /* notify main thread a line is ready */\r
1585}\r
1586\r
1587/* my_yield - process GUI messages. It's not apparent why stuff_and_wait would block,\r
1588 * since it sleeps in the GUI thread while scp runs in the main thread. However,\r
1589 * at the end of every command scp calls update_gui, which can result in messages\r
1590 * being sent to the GUI thread. So, the GUI thread has to process messages while\r
1591 * stuff_and_wait is waiting.\r
1592 */\r
1593static void my_yield (void)\r
1594{\r
1595 MSG msg;\r
1596 /* multitask */\r
1597 while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {\r
1598 TranslateMessage(&msg);\r
1599 DispatchMessage(&msg);\r
1600 }\r
1601}\r
1602\r
1603/* stuff_and_wait -- stuff a command and wait for the emulator to process the command\r
1604 * and come back to prompt for another\r
1605 */\r
1606\r
1607t_bool stuff_and_wait (char *cmd, int timeout, int delay)\r
1608{\r
1609 scp_reading = FALSE;\r
1610\r
1611 stuff_cmd(cmd);\r
1612\r
1613 while (! scp_reading) {\r
1614 if (timeout < 0)\r
1615 return FALSE;\r
1616\r
1617 my_yield();\r
1618 if (scp_reading)\r
1619 break;\r
1620\r
1621 Sleep(50);\r
1622 if (timeout)\r
1623 if ((timeout -= 50) <= 0)\r
1624 timeout = -1;\r
1625\r
1626 my_yield();\r
1627 }\r
1628\r
1629 if (delay)\r
1630 Sleep(delay);\r
1631\r
1632 return TRUE;\r
1633}\r
1634\r
1635/* remark_cmd - print a remark from inside a command processor. This routine takes\r
1636 * into account the possiblity that the command might have been stuffed, in which\r
1637 * case the sim> prompt needs to be reprinted.\r
1638 */\r
1639\r
1640void remark_cmd (char *remark)\r
1641{\r
1642 if (scp_reading) {\r
1643 putchar('\n');\r
1644 if (sim_log) putc('\n', sim_log);\r
1645 }\r
1646\r
1647 printf("%s\n", remark);\r
1648 if (sim_log) fprintf(sim_log, "%s\n", remark);\r
1649\r
1650 if (scp_reading) {\r
1651 printf("sim> ");\r
1652 if (sim_log) fprintf(sim_log, "sim> ");\r
1653 }\r
1654}\r
1655\r
1656#endif /* _WIN32 defined */\r
1657#endif /* GUI_SUPPORT defined */\r