|
|
1.1 root 1: /*
2: * UAE - The Un*x Amiga Emulator
3: *
4: * X interface
5: *
6: * Copyright 1995, 1996 Bernd Schmidt
7: * Copyright 1996 Ed Hanway, Andre Beck
8: */
9:
10: #include <stdio.h>
11: #include <stdlib.h>
12: #include <string.h>
13: #include <sys/time.h>
14: #include <X11/Xlib.h>
15: #include <X11/Xutil.h>
16: #include <X11/keysym.h>
17: #include <X11/cursorfont.h>
18:
19: #ifndef DONT_WANT_SHM
20: #include <sys/ipc.h>
21: #include <sys/shm.h>
22: #include <X11/extensions/XShm.h>
23: #endif
24:
25: #include "config.h"
26: #include "amiga.h"
27: #include "options.h"
28: #include "memory.h"
29: #include "custom.h"
30: #include "newcpu.h"
31: #include "xwin.h"
32: #include "keyboard.h"
33: #include "keybuf.h"
34:
35: #ifdef LINUX_SVGALIB
36: #error Compiling xwin.c, but LINUX_SVGALIB set. Re-edit "config.h".
37: #endif
38:
39: static Display *display;
40: static int screen;
41: static Window rootwin, mywin;
42:
43: static GC whitegc,blackgc;
44: static XColor black,white;
45: static Colormap cmap;
46:
47: static XImage *img;
48: static Visual *vis;
49: static XVisualInfo visualInfo;
50: static int bitdepth;
51: #ifndef DONT_WANT_SHM
52: static XShmSegmentInfo shminfo;
53: #endif
54: static Cursor blankCursor, xhairCursor;
55: static bool cursorOn;
56:
57: #ifdef DONT_WANT_SHM
58: static char pixel_buffer[3200];
59: #endif
60: static char *xlinestart;
61: char *xlinebuffer;
62: long int xcolors[4096];
63:
64: /* Keyboard and mouse */
65:
66: static bool keystate[256];
67:
68: bool buttonstate[3];
69: int lastmx, lastmy;
70: bool newmousecounters;
71: static bool inwindow;
72: const long int eventmask = (KeyPressMask|KeyReleaseMask|ButtonPressMask
73: |ButtonReleaseMask|PointerMotionMask
74: |FocusChangeMask|EnterWindowMask
75: |LeaveWindowMask);
76:
77: static bool next_line_double;
78: static int next_line_pos = 0;
79:
80: void flush_screen (void)
81: {
82: #ifndef DONT_WANT_SHM
83: if (next_line_pos > 0) {
84: XShmPutImage(display, mywin, blackgc, img, 0, 0, 0, 0, 796, next_line_pos, 0);
85: XSync(display, 0);
86: next_line_pos = 0;
87: }
88: #endif
89: }
90:
91: void prepare_line (int y, bool need_double)
92: {
93: next_line_double = need_double;
94: next_line_pos = y;
95:
96: #ifdef DONT_WANT_SHM
97: xlinebuffer = pixel_buffer;
98: #else
99: xlinestart = xlinebuffer = img->data + y * img->bytes_per_line;
100: #endif
101: }
102:
103: void flush_line(void)
104: {
105: #ifdef DONT_WANT_SHM
106: XPutImage(display, mywin, blackgc, img, 0, 0, 0, next_line_pos, 796, 1);
107: if (next_line_double)
108: XPutImage(display, mywin, blackgc, img, 0, 0, 0, next_line_pos+1, 796, 1);
109: #else
110: if (use_fast_draw && next_line_double) {
111: memcpy (xlinestart + img->bytes_per_line, xlinestart, img->bytes_per_line);
112: next_line_pos++; /* For flush_screen(). */
113: }
114: #endif
115: }
116:
117: #ifndef INLINE_DRAWPIXEL
118: void (*DrawPixel)(int, xcolnr);
119:
120: static void DrawPixel16(int x, xcolnr col)
121: {
122: *(short *)xlinebuffer = col;
123: xlinebuffer += 2;
124: }
125:
126: static void DrawPixel32(int x, xcolnr col)
127: {
128: *(long *)xlinebuffer = col;
129: xlinebuffer += 4;
130: }
131:
132: static void DrawPixel8(int x, xcolnr col)
133: {
134: *(char *)xlinebuffer = col;
135: xlinebuffer += 1;
136: }
137:
138: static void DrawPixelGeneric(int x, xcolnr col)
139: {
140: #ifdef DONT_WANT_SHM
141: XPutPixel(img, x, 0, col);
142: #else
143: XPutPixel(img, x, next_line_pos, col);
144: if (next_line_double) {
145: XPutPixel(img, x, next_line_pos+1, col);
146: }
147: #endif
148: }
149: #endif /* INLINE_DRAWPIXEL */
150:
151: #ifndef DONT_WANT_SHM
152: static void initShm(int depth)
153: {
154: int scale = dont_want_aspect ? 1 : 2;
155: img = XShmCreateImage(display, vis, depth,
156: ZPixmap, 0, &shminfo, 800, (313-29) * scale);
157:
158: shminfo.shmid = shmget(IPC_PRIVATE, 512*1024*scale, IPC_CREAT|0777);
159: shminfo.shmaddr = img->data = (char *)shmat(shminfo.shmid, 0, 0);
160: shminfo.readOnly = False;
161: /* let the xserver attach */
162: XShmAttach(display, &shminfo);
163: /* NOW ! */
164: XSync(display,0);
165: /* now deleting means making it temporary */
166: shmctl(shminfo.shmid, IPC_RMID, 0);
167:
168: xlinestart = xlinebuffer = img->data;
169: }
170: #endif
171:
172: static __inline__ int bitsInMask(unsigned long mask)
173: {
174: /* count bits in mask */
175: int n = 0;
176: while(mask) {
177: n += mask&1;
178: mask >>= 1;
179: }
180: return n;
181: }
182:
183: static __inline__ int maskShift(unsigned long mask)
184: {
185: /* determine how far mask is shifted */
186: int n = 0;
187: while(!(mask&1)) {
188: n++;
189: mask >>= 1;
190: }
191: return n;
192: }
193:
194: static __inline__ unsigned long doMask(int p, int bits, int shift)
195: {
196: /* p is a value from 0 to 15 (Amiga color value)
197: * scale to 0..255, shift to align msb with mask, and apply mask */
198:
199: unsigned long val = p * 0x11111111UL;
200: val >>= (32 - bits);
201: val <<= shift;
202:
203: return val;
204: }
205:
206: static void InitXColors(void)
207: {
208: #ifdef INLINE_DRAWPIXEL
209:
210: #ifdef X_8BIT_SCREEN
211: if (visualInfo.depth != 8) {
212: fprintf(stderr, "Unsupported bit depth (%d)\n", visualInfo.depth);
213: exit(1);
214: }
215: #endif
216:
217: #ifdef X_16BIT_SCREEN
218: if (visualInfo.depth != 12 && visualInfo.depth != 16) {
219: fprintf(stderr, "Unsupported bit depth (%d)\n", visualInfo.depth);
220: exit(1);
221: }
222: #endif
223:
224: #else /* not INLINE_DRAWPIXEL */
225: DrawPixel = DrawPixelGeneric;
226:
227: if(use_fast_draw) {
228: /* this is probably a lot faster but makes nonportable assumptions
229: * about image format */
230:
231: switch(visualInfo.depth) {
232: case 12:
233: DrawPixel = DrawPixel16;
234: break;
235:
236: case 24:
237: DrawPixel = DrawPixel32;
238: break;
239:
240: case 16:
241: DrawPixel = DrawPixel16;
242: break;
243:
244: case 8:
245: DrawPixel = DrawPixel8;
246: break;
247:
248: default:
249: fprintf(stderr, "Unsupported bit depth (%d)\n", visualInfo.depth);
250: exit(1);
251: }
252: }
253: #endif /* not INLINE_DRAWPIXEL */
254:
255: #ifdef __cplusplus
256: switch(visualInfo.c_class) {
257: #else
258: switch(visualInfo.class) {
259: #endif
260: case TrueColor:
261: {
262: int red_bits = bitsInMask(visualInfo.red_mask);
263: int green_bits = bitsInMask(visualInfo.green_mask);
264: int blue_bits = bitsInMask(visualInfo.blue_mask);
265: int red_shift = maskShift(visualInfo.red_mask);
266: int green_shift = maskShift(visualInfo.green_mask);
267: int blue_shift = maskShift(visualInfo.blue_mask);
268:
269: int i;
270: for(i = 0; i < 4096; i++) {
271: int r = i >> 8;
272: int g = (i >> 4) & 0xF;
273: int b = i & 0xF;
274: xcolors[i] = (doMask(r, red_bits, red_shift)
275: | doMask(g, green_bits, green_shift)
276: | doMask(b, blue_bits, blue_shift));
277: }
278: }
279: break;
280:
281: case GrayScale:
282: case PseudoColor:
283: {
284: /* This is kind of kludgy...
285: * Try to allocate as many different colors as possible. */
286: int col;
287: int step = 16;
288: int allocated[4096];
289: memset(allocated,0,sizeof allocated);
290:
291: while ((step/=2) > 0) {
292: int r, g, b;
293: for(r=0; r<16; r += step) {
294: for(g=0; g<16; g += step) {
295: for(b=0; b<16; b += step) {
296: int cnr = (r << 8) + (g << 4) + b;
297: if (!allocated[cnr]) {
298: XColor col;
299: char str[10];
300: sprintf(str, "rgb:%x/%x/%x", r,g,b);
301: XParseColor(display,cmap,str,&col);
302: if (XAllocColor(display,cmap,&col)) {
303: allocated[cnr] = true;
304: xcolors[cnr] = col.pixel;
305: }
306: }
307: }
308: }
309: }
310: }
311:
312: for(col = 0; col < 4096; col++) {
313: int cnr = col;
314: if (!allocated[cnr]) {
315: int r = cnr >> 8;
316: int g = (cnr >> 4) & 0xF;
317: int b = cnr & 0xF;
318: int maxd = 4096,best = 0;
319: int c2;
320: for(c2 = 0; c2 < 4096; c2++)
321: if (allocated[c2]) {
322: int r2 = c2 >> 8;
323: int g2 = (c2 >> 4) & 0xF;
324: int b2 = c2 & 0xF;
325: int dist = abs(r2-r)*2 + abs(g2-g)*3 + abs(b2-b);
326: if (dist < maxd) {
327: maxd = dist;
328: best = c2;
329: }
330: }
331: cnr = best;
332: }
333: xcolors[col] = xcolors[cnr];
334:
335: }
336: }
337: break;
338:
339: default:
340: #ifdef __cplusplus
341: fprintf(stderr, "Unsupported class (%d)\n", visualInfo.c_class);
342: #else
343: fprintf(stderr, "Unsupported class (%d)\n", visualInfo.class);
344: #endif
345: exit(1);
346: }
347: }
348:
349: void graphics_init(void)
350: {
351: int i;
352: char *display_name = 0;
353: XSetWindowAttributes wattr;
354: int vscale = dont_want_aspect ? 1 : 2;
355:
356: display = XOpenDisplay(display_name);
357: if (display == 0) {
358: fprintf(stderr, "Can't connect to X server %s\n", XDisplayName(display_name));
359: exit(-1);
360: }
361: screen = XDefaultScreen(display);
362: rootwin = XRootWindow(display,screen);
363:
364: /* try for a 12 bit visual first, then a 16 bit, then a 24 bit, then 8 bit */
365: if (XMatchVisualInfo(display, screen, 12, TrueColor, &visualInfo)) {
366: } else if (XMatchVisualInfo(display, screen, 16, TrueColor, &visualInfo)) {
367: } else if (XMatchVisualInfo(display, screen, 24, TrueColor, &visualInfo)) {
368: } else if (XMatchVisualInfo(display, screen, 8, PseudoColor, &visualInfo)) {
369: /* for our HP boxes */
370: } else if (XMatchVisualInfo(display, screen, 8, GrayScale, &visualInfo)) {
371: } else {
372: fprintf(stderr, "Can't obtain appropriate X visual\n");
373: exit(1);
374: }
375:
376: vis = visualInfo.visual;
377: bitdepth = visualInfo.depth;
378:
379: fprintf(stderr, "Using %d bit visual\n", bitdepth);
380:
381: cmap = XCreateColormap(display, rootwin, vis, AllocNone);
382: XParseColor(display, cmap, "#000000", &black);
383: if (!XAllocColor(display, cmap, &black))
384: fprintf(stderr, "Whoops??\n");
385: XParseColor(display, cmap, "#ffffff", &white);
386: if (!XAllocColor(display, cmap, &white))
387: fprintf(stderr, "Whoops??\n");
388:
389: wattr.event_mask = eventmask;
390: wattr.background_pixel = black.pixel;
391: wattr.backing_store = Always;
392: wattr.backing_planes = bitdepth;
393: wattr.border_pixmap = None;
394: wattr.border_pixel = black.pixel;
395: wattr.colormap = cmap;
396:
397: mywin = XCreateWindow(display,rootwin,0,0,796,vscale*(313-29),0,
398: bitdepth, InputOutput, vis,
399: CWEventMask|CWBackPixel|CWBorderPixel|CWBackingStore
400: |CWBackingPlanes|CWColormap,
401: &wattr);
402: XMapWindow(display,mywin);
403:
404: blankCursor = XCreatePixmapCursor(display,
405: XCreatePixmap(display, mywin, 1, 1, 1),
406: XCreatePixmap(display, mywin, 1, 1, 1),
407: &black, &white, 0, 0);
408: xhairCursor = XCreateFontCursor(display, XC_crosshair);
409:
410: whitegc = XCreateGC(display,mywin,0,0);
411: blackgc = XCreateGC(display,mywin,0,0);
412:
413: XSetForeground(display,blackgc,black.pixel);
414: XSetForeground(display,whitegc,white.pixel);
415:
416: #ifdef DONT_WANT_SHM
417: img = XCreateImage(display, vis, bitdepth, ZPixmap, 0, pixel_buffer, 800,
418: 1, 32, 0);
419: #else
420: initShm (bitdepth);
421: #endif
422: InitXColors();
423: buttonstate[0] = buttonstate[1] = buttonstate[2] = false;
424: for(i=0; i<256; i++) keystate[i] = false;
425:
426: lastmx = lastmy = 0; newmousecounters = false; inwindow = false;
427: XDefineCursor(display, mywin, xhairCursor);
428: cursorOn = true;
429: }
430:
431: void graphics_leave(void)
432: {
433: XAutoRepeatOn(display);
434: }
435:
436: /* Decode KeySyms. This function knows about all keys that are common
437: * between different keyboard languages. */
438: static int kc_decode (KeySym ks)
439: {
440: switch (ks) {
441: case XK_A: case XK_a: return AK_A;
442: case XK_B: case XK_b: return AK_B;
443: case XK_C: case XK_c: return AK_C;
444: case XK_D: case XK_d: return AK_D;
445: case XK_E: case XK_e: return AK_E;
446: case XK_F: case XK_f: return AK_F;
447: case XK_G: case XK_g: return AK_G;
448: case XK_H: case XK_h: return AK_H;
449: case XK_I: case XK_i: return AK_I;
450: case XK_J: case XK_j: return AK_J;
451: case XK_K: case XK_k: return AK_K;
452: case XK_L: case XK_l: return AK_L;
453: case XK_M: case XK_m: return AK_M;
454: case XK_N: case XK_n: return AK_N;
455: case XK_O: case XK_o: return AK_O;
456: case XK_P: case XK_p: return AK_P;
457: case XK_Q: case XK_q: return AK_Q;
458: case XK_R: case XK_r: return AK_R;
459: case XK_S: case XK_s: return AK_S;
460: case XK_T: case XK_t: return AK_T;
461: case XK_U: case XK_u: return AK_U;
462: case XK_V: case XK_v: return AK_V;
463: case XK_W: case XK_w: return AK_W;
464: case XK_X: case XK_x: return AK_X;
465:
466: case XK_0: return AK_0;
467: case XK_1: return AK_1;
468: case XK_2: return AK_2;
469: case XK_3: return AK_3;
470: case XK_4: return AK_4;
471: case XK_5: return AK_5;
472: case XK_6: return AK_6;
473: case XK_7: return AK_7;
474: case XK_8: return AK_8;
475: case XK_9: return AK_9;
476:
477: case XK_KP_0: return AK_NP0;
478: case XK_KP_1: return AK_NP1;
479: case XK_KP_2: return AK_NP2;
480: case XK_KP_3: return AK_NP3;
481: case XK_KP_4: return AK_NP4;
482: case XK_KP_5: return AK_NP5;
483: case XK_KP_6: return AK_NP6;
484: case XK_KP_7: return AK_NP7;
485: case XK_KP_8: return AK_NP8;
486: case XK_KP_9: return AK_NP9;
487:
488: case XK_F1: return AK_F1;
489: case XK_F2: return AK_F2;
490: case XK_F3: return AK_F3;
491: case XK_F4: return AK_F4;
492: case XK_F5: return AK_F5;
493: case XK_F6: return AK_F6;
494: case XK_F7: return AK_F7;
495: case XK_F8: return AK_F8;
496: case XK_F9: return AK_F9;
497: case XK_F10: return AK_F10;
498:
499: case XK_BackSpace: case XK_Delete: return AK_BS;
500: case XK_Control_L: return AK_CTRL;
501: case XK_Tab: return AK_TAB;
502: case XK_Alt_L: case XK_Meta_L: return AK_LALT;
503: case XK_Alt_R: case XK_Meta_R: return AK_RALT;
504: case XK_Return: return AK_RET;
505: case XK_space: return AK_SPC;
506: case XK_Shift_L: return AK_LSH;
507: case XK_Shift_R: return AK_RSH;
508: case XK_Escape: return AK_ESC;
509:
510: case XK_Up: return AK_UP;
511: case XK_Down: return AK_DN;
512: case XK_Left: return AK_LF;
513: case XK_Right: return AK_RT;
514:
515: case XK_F11: return AK_BACKSLASH;
516: case XK_F12: return AK_mousestuff;
517: case XK_Scroll_Lock: return AK_inhibit;
518:
519: #ifdef XK_Page_Up /* These are missing occasionally */
520: case XK_Page_Up: return AK_RAMI; /* PgUp mapped to right amiga */
521: case XK_Page_Down: return AK_LAMI; /* PgDn mapped to left amiga */
522: #endif
523: }
524: return -1;
525: }
526:
527: static int decode_us(KeySym ks)
528: {
529: switch(ks) { /* US specific */
530: case XK_Y: case XK_y: return AK_Y;
531: case XK_Z: case XK_z: return AK_Z;
532: case XK_bracketleft: return AK_LBRACKET;
533: case XK_bracketright: return AK_RBRACKET;
534: case XK_comma: return AK_COMMA;
535: case XK_period: return AK_PERIOD;
536: case XK_slash: return AK_SLASH;
537: case XK_semicolon: return AK_SEMICOLON;
538: case XK_minus: return AK_MINUS;
539: case XK_equal: return AK_EQUAL;
540: /* this doesn't work: */
541: case XK_grave: return AK_QUOTE;
542: }
543:
544: return -1;
545: }
546:
547: static int decode_de(KeySym ks)
548: {
549: switch(ks) {
550: /* DE specific */
551: case XK_Y: case XK_y: return AK_Z;
552: case XK_Z: case XK_z: return AK_Y;
553: case XK_Odiaeresis: case XK_odiaeresis: return AK_SEMICOLON;
554: case XK_Adiaeresis: case XK_adiaeresis: return AK_QUOTE;
555: case XK_Udiaeresis: case XK_udiaeresis: return AK_LBRACKET;
556: case XK_plus: case XK_asterisk: return AK_RBRACKET;
557: case XK_comma: return AK_COMMA;
558: case XK_period: return AK_PERIOD;
559: case XK_less: case XK_greater: return AK_LTGT;
560: case XK_numbersign: return AK_NUMBERSIGN;
561: case XK_ssharp: return AK_MINUS;
562: case XK_apostrophe: return AK_EQUAL;
563: case XK_asciicircum: return AK_00;
564: case XK_minus: return AK_SLASH;
565: }
566:
567: return -1;
568: }
569:
570: static int keycode2amiga(XKeyEvent *event)
571: {
572: KeySym ks;
573: int as;
574: int index = 0;
575:
576: do {
577: ks = XLookupKeysym(event, index);
578: as = kc_decode (ks);
579:
580: if (as == -1) {
581: switch(keyboard_lang) {
582: case KBD_LANG_US:
583: as = decode_us(ks);
584: break;
585:
586: case KBD_LANG_DE:
587: as = decode_de(ks);
588: break;
589:
590: default:
591: as = -1;
592: break;
593: }
594: }
595: if(-1 != as)
596: return as;
597: index++;
598: } while (ks != NoSymbol);
599: return -1;
600: }
601:
602: static struct timeval lastMotionTime;
603:
604: void handle_events(void)
605: {
606: bool repeat;
607: newmousecounters = false;
608: do {
609: XEvent event;
610: if (!XCheckMaskEvent(display, eventmask, &event)) break;
611: repeat = false;
612:
613: switch(event.type) {
614: case KeyPress: {
615: int kc = keycode2amiga((XKeyEvent *)&event);
616: if (kc == -1) break;
617: switch (kc) {
618: case AK_mousestuff:
619: #if 0
620: if (keystate[AK_CTRL])
621: mousesetup();
622: else
623: #endif
624: togglemouse();
625: break;
626:
627: case AK_inhibit:
628: inhibit_frame ^= 1;
629: break;
630:
631: default:
632: if (!keystate[kc]) {
633: keystate[kc] = true;
634: record_key (kc << 1);
635: }
636: break;
637: }
638: break;
639: }
640: case KeyRelease: {
641: int kc = keycode2amiga((XKeyEvent *)&event);
642: if (kc == -1) break;
643: keystate[kc] = false;
644: record_key ((kc << 1) | 1);
645: break;
646: }
647: case ButtonPress:
648: buttonstate[((XButtonEvent *)&event)->button-1] = true;
649: break;
650: case ButtonRelease:
651: buttonstate[((XButtonEvent *)&event)->button-1] = false;
652: break;
653: case EnterNotify:
654: newmousecounters = true;
655: lastmx = ((XCrossingEvent *)&event)->x;
656: lastmy = ((XCrossingEvent *)&event)->y;
657: repeat = true;
658: inwindow = true;
659: break;
660: case LeaveNotify:
661: inwindow = false;
662: repeat = true;
663: break;
664: case FocusIn:
665: XAutoRepeatOff(display);
666: repeat = true;
667: break;
668: case FocusOut:
669: XAutoRepeatOn(display);
670: repeat = true;
671: break;
672: case MotionNotify:
673: if (inwindow) {
674: lastmx = ((XMotionEvent *)&event)->x;
675: lastmy = ((XMotionEvent *)&event)->y;
676: if(!cursorOn) {
677: XDefineCursor(display, mywin, xhairCursor);
678: cursorOn = true;
679: }
680: gettimeofday(&lastMotionTime, NULL);
681: }
682: repeat = true;
683: break;
684: }
685: } while (repeat);
686:
687: if(cursorOn) {
688: struct timeval now;
689: int diff;
690: gettimeofday(&now, NULL);
691: diff = (now.tv_sec - lastMotionTime.tv_sec) * 1000000 +
692: (now.tv_usec - lastMotionTime.tv_usec);
693: if(diff > 1000000) {
694: XDefineCursor(display, mywin, blankCursor);
695: cursorOn = false;
696: }
697: }
698:
699: /* "Affengriff" */
700: if(keystate[AK_CTRL] && keystate[AK_LAMI] && keystate[AK_RAMI])
701: MC68000_reset();
702: }
703:
704: bool debuggable(void)
705: {
706: return true;
707: }
708:
709: bool needmousehack(void)
710: {
711: return true;
712: }
713:
714: void LED(int on)
715: {
716: XKeyboardControl control;
717: control.led = 1; /* implementation defined */
718: control.led_mode = on ? LedModeOn : LedModeOff;
719: XChangeKeyboardControl(display, KBLed | KBLedMode, &control);
720: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.