1 /****************************************************************************
2 * *
3 * Third Year Project *
4 * *
5 * An IBM PC Emulator *
6 * For Unix and X Windows *
7 * *
8 * By David Hedley *
9 * *
10 * *
11 * This program is Copyrighted. Consult the file COPYRIGHT for more details *
12 * *
13 ****************************************************************************/
14
15 #include "global.h"
16
17 #include <X11/Xlib.h>
18 #include <X11/Xutil.h>
19 #include <X11/Xos.h>
20 #include <X11/Xatom.h>
21 #include <X11/keysym.h>
22 #include <stdio.h>
23
24 #include "icon.h"
25 #include "xstuff.h"
26 #include "vgahard.h"
27 #include "hardware.h"
28
29 #define BITMAPDEPTH 1
30
31 static Display *display;
32 static int screen_num;
33 static XFontStruct *font_info;
34 static GC gc, cursorgc;
35 static Pixmap under_cursor;
36 static Window win;
37 static XSizeHints size_hints;
38
39 static int font_height;
40 static int font_width;
41 static int font_descent;
42
43 static int cx, cy, cs, chgt;
44
45 int blink, graphics;
46 extern int mono;
47
48 struct
49 {
50 unsigned r,g,b;
51 } text_cols[] =
52 {
53 {0,0,0},{10,10,185},{10,195,10},{20,160,160},
54 {167,10,10},{167,0,167},{165,165,40},{197,197,197},
55 {100,100,100},{10,10,255},{10,255,10},{10,255,255},
56 {255,10,10},{255,10,255},{255,255,0},{255,255,255}
57 };
58
59 unsigned col_vals[16];
60 unsigned blink_vals[16];
61
get_colours(void)62 void get_colours(void)
63 {
64 XColor col;
65 int i;
66
67 if (mono)
68 {
69 col_vals[0] = BlackPixel(display, screen_num);
70
71 for (i = 1; i < 16; i++)
72 col_vals[i] = WhitePixel(display, screen_num);
73 }
74 else
75 {
76 col.flags = DoRed | DoGreen | DoBlue;
77 for(i = 0; i < 16; i++)
78 {
79 col.red=text_cols[i].r << 8;
80 col.green=text_cols[i].g << 8;
81 col.blue=text_cols[i].b << 8;
82 XAllocColor(display, DefaultColormap(display, screen_num),
83 &col);
84 col_vals[i] = col.pixel;
85 }
86 }
87 }
88
89
put_cursor(unsigned x,unsigned y)90 void put_cursor(unsigned x, unsigned y)
91 {
92 if (chgt < 1)
93 return;
94
95 cx = x*font_width;
96 cy = y*font_height+cs+font_descent;
97
98 XCopyArea(display, win, under_cursor, cursorgc, cx, cy, font_width,
99 chgt, 0, 0);
100 XFillRectangle(display, win, cursorgc, cx, cy, font_width, chgt);
101 }
102
103
unput_cursor(void)104 void unput_cursor(void)
105 {
106 if (chgt < 1)
107 return;
108
109 XCopyArea(display, under_cursor, win, cursorgc, 0, 0, font_width, chgt,
110 cx, cy);
111 }
112
new_cursor(int st,int end)113 void new_cursor(int st, int end)
114 {
115 cs = st;
116 chgt = end - st + 1;
117 }
118
setGC(void)119 static void setGC(void)
120 {
121 unsigned long valuemask = 0; /* ignore XGCvalues and use defaults */
122 XGCValues values;
123 unsigned int line_width = 6;
124 int line_style = LineOnOffDash;
125 int cap_style = CapRound;
126 int join_style = JoinRound;
127
128 gc = XCreateGC(display, win, valuemask, &values);
129 cursorgc = XCreateGC(display, win, valuemask, &values);
130
131 XSetFont(display, gc, font_info->fid);
132 XSetForeground(display, gc, WhitePixel(display,screen_num));
133 XSetBackground(display, gc, BlackPixel(display,screen_num));
134
135 XSetLineAttributes(display, gc, line_width, line_style,
136 cap_style, join_style);
137
138 XSetForeground(display, cursorgc, WhitePixel(display,screen_num));
139 XSetBackground(display, cursorgc, BlackPixel(display,screen_num));
140 }
141
142
setcursor(void)143 static void setcursor(void)
144 {
145 under_cursor = XCreatePixmap(display, win, font_width, font_height,
146 DefaultDepth(display, screen_num));
147 }
148
load_font(void)149 static void load_font(void)
150 {
151 static char *fontname = "vga";
152 static char *fontname2 = "8x16";
153 char string[] = "W";
154
155 if ((font_info = XLoadQueryFont(display, fontname)) == NULL)
156 {
157 fprintf(stderr,"Warning: cannot locate correct VGA font\n"
158 "Reverting to standard 8x16 font\n");
159 if ((font_info = XLoadQueryFont(display, fontname2)) == NULL)
160 {
161 fprintf(stderr, "%s: Cannot open 8x16 font\n",
162 progname);
163 exit(1);
164 }
165 }
166 font_height = font_info->ascent + font_info->descent;
167 font_width = XTextWidth(font_info, string, 1);
168 font_descent = font_info->descent;
169 }
170
171
clear_screen(void)172 void clear_screen(void)
173 {
174 XClearWindow(display, win);
175 }
176
177
copy(unsigned x1,unsigned y1,unsigned x2,unsigned y2,unsigned nx,unsigned ny)178 void copy(unsigned x1, unsigned y1, unsigned x2, unsigned y2,
179 unsigned nx, unsigned ny)
180 {
181 x1 *= font_width;
182 y1 *= font_height;
183 x2 = (x2+1)*font_width;
184 y2 = (y2+1)*font_height;
185 nx *= font_width;
186 ny *= font_height;
187
188 XCopyArea(display, win, win, gc, x1, y1+font_descent, x2-x1, y2-y1, nx,
189 ny+font_descent);
190 }
191
192
draw_line(unsigned x,unsigned y,char * text,unsigned len,BYTE attr)193 void draw_line(unsigned x, unsigned y, char *text, unsigned len, BYTE attr)
194 {
195 XSetForeground(display, gc, col_vals[attr & 0xf]);
196 XSetBackground(display, gc, col_vals[(attr & 0x70) >> 4]);
197 XDrawImageString(display, win, gc,
198 x*font_width, (y+1)*font_height, text, len);
199 }
200
201
draw_char(unsigned x,unsigned y,char c,BYTE attr)202 void draw_char(unsigned x, unsigned y, char c, BYTE attr)
203 {
204 XSetForeground(display, gc, col_vals[attr & 0xf]);
205 XSetBackground(display, gc, col_vals[(attr & 0x70) >> 4]);
206 XDrawImageString(display, win, gc,
207 x*font_width, (y+1)*font_height, &c, 1);
208 }
209
210
window_size(unsigned width,unsigned height)211 void window_size(unsigned width, unsigned height)
212 {
213 width *= font_width;
214 height = height*font_height+4;
215
216 D(printf("Window size = %dx%d\n", width, height););
217 XResizeWindow(display, win, width, height);
218
219 size_hints.flags = PSize | PMinSize | PMaxSize;
220 size_hints.max_width = size_hints.min_width = width;
221 size_hints.max_height = size_hints.min_height = height;
222
223 XSetWMNormalHints(display, win, &size_hints);
224 }
225
226
start_X(void)227 void start_X(void)
228 {
229 unsigned int width, height; /* window size */
230 int x, y; /* window position */
231 unsigned int border_width = 4; /* four pixels */
232 unsigned int display_width, display_height;
233 char *display_name = NULL;
234 XWMHints wm_hints;
235 char *window_name = "PC Emulator";
236 char *icon_name = "PC";
237 XClassHint class_hints;
238 XTextProperty windowName, iconName;
239 Pixmap icon_pixmap;
240
241 if ((display=XOpenDisplay(display_name)) == NULL)
242 {
243 fprintf(stderr, "%s: cannot connect to X server %s\n",
244 progname, XDisplayName(display_name));
245 exit(1);
246 }
247
248 screen_num = DefaultScreen(display);
249 display_width = DisplayWidth(display, screen_num);
250 display_height = DisplayHeight(display, screen_num);
251
252 x = y = 0;
253
254 load_font();
255
256 width = 80*font_width;
257 height = 25*font_height+4;
258
259 win = XCreateSimpleWindow(display, RootWindow(display,screen_num),
260 x, y, width, height, border_width,
261 WhitePixel(display, screen_num),
262 BlackPixel(display,screen_num));
263
264 icon_pixmap = XCreateBitmapFromData(display, win, icon_bits,
265 icon_width, icon_height);
266
267 if (XStringListToTextProperty(&window_name, 1, &windowName) == 0)
268 {
269 fprintf(stderr, "%s: structure allocation for windowName failed.\n",
270 progname);
271 exit(1);
272 }
273
274 if (XStringListToTextProperty(&icon_name, 1, &iconName) == 0)
275 {
276 fprintf(stderr, "%s: structure allocation for iconName failed.\n",
277 progname);
278 exit(1);
279 }
280
281 size_hints.flags = PSize | PMinSize | PMaxSize;
282 size_hints.max_width = size_hints.min_width = width;
283 size_hints.max_height = size_hints.min_height = height;
284
285 wm_hints.initial_state = NormalState;
286 wm_hints.input = True;
287 wm_hints.icon_pixmap = icon_pixmap;
288 wm_hints.flags = StateHint | IconPixmapHint | InputHint;
289
290 class_hints.res_name = progname;
291 class_hints.res_class = "PCEmulator";
292
293 XSetWMProperties(display, win, &windowName, &iconName,
294 &progname, 1, &size_hints, &wm_hints,
295 &class_hints);
296
297 XSelectInput(display, win, ExposureMask | KeyPressMask | KeyReleaseMask |
298 StructureNotifyMask);
299
300 setGC();
301 setcursor();
302
303 mono = (DisplayCells(display, screen_num) < 16);
304 graphics = 0; /* !(DisplayCells(display, screen_num) < 256); */
305
306 get_colours();
307
308 /* Display window */
309 XMapWindow(display, win);
310 }
311
312
flush_X(void)313 void flush_X(void)
314 {
315 XFlush(display);
316 }
317
318
319 static BYTE scan_table1[] =
320 {
321 0x39, 0x02,
322 #ifdef KBUK /* double quotes, hash symbol */
323 0x03, 0x2b,
324 #else
325 0x28, 0x04,
326 #endif
327 0x05, 0x06, 0x08, 0x28,
328 0x0a, 0x0b, 0x09, 0x0d, 0x33, 0x0c, 0x34, 0x35,
329 0x0b, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
330 0x09, 0x0a, 0x27, 0x27, 0x33, 0x0d, 0x34, 0x35,
331 #ifdef KBUK /* at symbol */
332 0x28,
333 #else
334 0x03,
335 #endif
336 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22,
337 0x23, 0x17, 0x24, 0x25, 0x26, 0x32, 0x31, 0x18,
338 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11,
339 0x2d, 0x15, 0x2c, 0x1a,
340 #ifdef KBUK /* backslash */
341 0x56,
342 #else
343 0x2b,
344 #endif
345 0x1b, 0x07, 0x0c,
346 0x29, 0x1e, 0x30, 0x2e, 0x20, 0x12, 0x21, 0x22,
347 0x23, 0x17, 0x24, 0x25, 0x26, 0x32, 0x31, 0x18,
348 0x19, 0x10, 0x13, 0x1f, 0x14, 0x16, 0x2f, 0x11,
349 0x2d, 0x15, 0x2c, 0x1a,
350 #ifdef KBUK /* vertical bar */
351 0x56,
352 #else
353 0x2b,
354 #endif
355
356 0x1b,
357
358 #ifdef KBUK /* tilde */
359 0x2b,
360 #else
361 0x29,
362 #endif
363 };
364
365
366 static struct
367 {
368 KeySym key;
369 unsigned scan_code;
370 } scan_table2[] =
371 {
372 { XK_BackSpace, 0x0e },
373 { XK_Tab, 0x0f },
374 { XK_Return, 0x1c },
375 { XK_Escape, 0x01 },
376 { XK_Delete, 0x53e0 },
377
378 { XK_Home, 0x47e0 },
379 { XK_Left, 0x4be0 },
380 { XK_Up, 0x48e0 },
381 { XK_Right, 0x4de0 },
382 { XK_Down, 0x50e0 },
383 { XK_Prior, 0x49e0 },
384 { XK_Next, 0x51e0 },
385 { XK_End, 0x4fe0 },
386 { XK_Insert, 0x52e0 },
387 { XK_Num_Lock, 0x45 },
388
389 /* This block of codes is for Sun Type 4 keyboards... */
390
391 { XK_F27, 0x47e0 }, /* Home/R7/F27 */
392 { XK_F29, 0x49e0 }, /* Prior/R9/F29 */
393 { XK_F35, 0x51e0 }, /* Next/R15/F35 */
394 { XK_F33, 0x4fe0 }, /* End/R13/F33 */
395
396 { XK_F25, 0x36e0 }, /* Keypad divide/R5/F25 */
397 { XK_F26, 0x37 }, /* Keypad multiply/R6/F26 */
398
399 { XK_F23, 0x46 }, /* Scroll lock/R3/F23 */
400
401 { XK_F31, 0x4c }, /* Keypad 5/R11/F31 */
402
403 /* End of Sun type 4 codes */
404
405 { XK_KP_Enter, 0x1ce0 },
406 { XK_KP_Multiply, 0x37 },
407 { XK_KP_Add, 0x4e },
408 { XK_KP_Subtract, 0x4a },
409 { XK_KP_Divide, 0x36e0 },
410 { XK_KP_Decimal, 0x53 },
411
412 { XK_KP_0, 0x52 },
413 { XK_KP_1, 0x4f },
414 { XK_KP_2, 0x50 },
415 { XK_KP_3, 0x51 },
416 { XK_KP_4, 0x4b },
417 { XK_KP_5, 0x4c },
418 { XK_KP_6, 0x4d },
419 { XK_KP_7, 0x47 },
420 { XK_KP_8, 0x48 },
421 { XK_KP_9, 0x49 },
422
423 { XK_F1, 0x3b },
424 { XK_F2, 0x3c },
425 { XK_F3, 0x3d },
426 { XK_F4, 0x3e },
427 { XK_F5, 0x3f },
428 { XK_F6, 0x40 },
429 { XK_F7, 0x41 },
430 { XK_F8, 0x42 },
431 { XK_F9, 0x43 },
432 { XK_F10, 0x44 },
433 { XK_F11, 0x57 },
434 { XK_F12, 0x58 },
435
436 { XK_Shift_L, 0x2a },
437 { XK_Shift_R, 0x36 },
438 { XK_Control_L, 0x1d },
439 { XK_Control_R, 0x1de0 },
440 { XK_Meta_L, 0x38 },
441 { XK_Alt_L, 0x38 },
442 { XK_Meta_R, 0x38e0 },
443 { XK_Alt_R, 0x38e0 },
444
445 { XK_Scroll_Lock, 0x46 },
446 { XK_Caps_Lock, 0xba3a }
447 };
448
449
translate(KeySym key)450 static unsigned translate(KeySym key)
451 {
452 int i;
453 if (key >= 0x20 && key <= 0x20+sizeof(scan_table1))
454 return (scan_table1[key - 0x20]);
455
456 for (i = 0; i < sizeof(scan_table2); i++)
457 if (scan_table2[i].key == key)
458 return (scan_table2[i].scan_code);
459
460 return 0;
461 }
462
463
process_Xevents(void)464 void process_Xevents(void)
465 {
466 #define KEY_BUFFER_SIZE 100
467
468 XEvent event;
469 KeySym key;
470 unsigned scan;
471 static BYTE buffer[4];
472 XEvent keyeventbuffer[KEY_BUFFER_SIZE];
473 int keyptr = 0;
474 int count;
475
476 while (XPending(display) > 0)
477 {
478 XNextEvent(display, &event);
479 switch(event.type)
480 {
481 case Expose:
482 if (event.xexpose.count != 0)
483 break;
484
485 refresh();
486 break;
487 case UnmapNotify: /* Pause emulator */
488 stoptimer();
489 for (;;)
490 {
491 XNextEvent(display, &event);
492 switch(event.type)
493 {
494 case MapNotify:
495 starttimer();
496 return;
497 default:
498 break;
499 }
500 }
501 break;
502 case KeyPress:
503 case KeyRelease:
504 key = XLookupKeysym(&event.xkey, 0);
505
506 D(printf("State = %X. Got keysym number: %X\n",
507 (int)event.xkey.state, (int)key););
508
509 /* XK_F21 is for sun type 4 keyboards.. */
510 if (key == XK_Break | key == XK_F21)
511 key = XK_Pause;
512
513 if (key == XK_Pause)
514 {
515 D(printf("Pause pressed. State = %02X\n", event.xkey.state););
516 if (event.xkey.state & ControlMask)
517 scan = 0xc6e046e0;
518 else
519 scan = 0x451de1;
520 } /* XK_F22 is sun type 4 PrtScr */
521 else if (key == XK_Print || key == XK_F22)
522 {
523 D(printf("Print pressed. State = %02X\n", event.xkey.state););
524 if (event.xkey.state & Mod1Mask)
525 scan = 0x54;
526 else
527 scan = 0x37e02ae0;
528 }
529 #ifdef KBUK
530 else if ((key == XK_numbersign) && (event.xkey.state & ShiftMask))
531 scan = 0x4;
532 #endif
533 else if (key == XK_sterling)
534 scan = 0x4;
535 else if ((scan = translate(key)) == 0)
536 break;
537
538 for (count = 0; scan; count++)
539 {
540 if (key != XK_Caps_Lock && event.type == KeyRelease)
541 buffer[count] = 0x80 | (scan & 0xff);
542 else
543 buffer[count] = scan & 0xff;
544
545 scan >>= 8;
546 }
547
548 if (port60_buffer_ok(count))
549 {
550 D(printf("Returning %d scan code bytes\n",count););
551 put_scancode(buffer, count);
552 }
553 else
554 {
555 D(printf("Port60 buffer full...\n"););
556
557 if (keyptr < KEY_BUFFER_SIZE)
558 keyeventbuffer[keyptr++] = event;
559 }
560
561 break;
562 default:
563 break;
564 }
565 }
566
567 for (count = keyptr; count > 0; count--)
568 XPutBackEvent(display, &keyeventbuffer[count-1]);
569 }
570
571
end_X(void)572 void end_X(void)
573 {
574 XUnloadFont(display, font_info->fid);
575 XFreeGC(display, gc);
576 XFreeGC(display, cursorgc);
577 XFreePixmap(display, under_cursor);
578 XCloseDisplay(display);
579 }
580
581