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