1 |
/* |
2 |
* Display_x.h - C64 graphics display, emulator window handling, |
3 |
* X specific stuff |
4 |
* |
5 |
* Frodo (C) 1994-1997,2002-2005 Christian Bauer |
6 |
* |
7 |
* This program is free software; you can redistribute it and/or modify |
8 |
* it under the terms of the GNU General Public License as published by |
9 |
* the Free Software Foundation; either version 2 of the License, or |
10 |
* (at your option) any later version. |
11 |
* |
12 |
* This program is distributed in the hope that it will be useful, |
13 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 |
* GNU General Public License for more details. |
16 |
* |
17 |
* You should have received a copy of the GNU General Public License |
18 |
* along with this program; if not, write to the Free Software |
19 |
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
20 |
*/ |
21 |
|
22 |
#include "SAM.h" |
23 |
#include "C64.h" |
24 |
|
25 |
#include <X11/Xlib.h> |
26 |
#include <X11/Xutil.h> |
27 |
#include <X11/keysym.h> |
28 |
#include <X11/cursorfont.h> |
29 |
|
30 |
#if defined(X_USE_SHM) |
31 |
#include <sys/ipc.h> |
32 |
#include <sys/shm.h> |
33 |
#include <X11/extensions/XShm.h> |
34 |
static XShmSegmentInfo shminfo; |
35 |
#endif |
36 |
|
37 |
static Display *display; |
38 |
static int screen; |
39 |
static Window rootwin, mywin; |
40 |
|
41 |
static GC black_gc, led_gc; |
42 |
static XColor black, fill_gray, shine_gray, shadow_gray, red, green; |
43 |
static Colormap cmap; |
44 |
static Font led_font; |
45 |
|
46 |
static XImage *img; |
47 |
static Visual *vis; |
48 |
static XVisualInfo visualInfo; |
49 |
static int bitdepth; |
50 |
static char *bufmem; |
51 |
static int hsize; |
52 |
|
53 |
// For LED error blinking |
54 |
static C64Display *c64_disp; |
55 |
static struct sigaction pulse_sa; |
56 |
static itimerval pulse_tv; |
57 |
|
58 |
// Keyboard and joystick |
59 |
static int keystate[256]; |
60 |
static int joystate = 0xFF; |
61 |
static bool num_locked = false; |
62 |
|
63 |
static const long int eventmask = (KeyPressMask|KeyReleaseMask|FocusChangeMask|ExposureMask); |
64 |
|
65 |
|
66 |
/* |
67 |
C64 keyboard matrix: |
68 |
|
69 |
Bit 7 6 5 4 3 2 1 0 |
70 |
0 CUD F5 F3 F1 F7 CLR RET DEL |
71 |
1 SHL E S Z 4 A W 3 |
72 |
2 X T F C 6 D R 5 |
73 |
3 V U H B 8 G Y 7 |
74 |
4 N O K M 0 J I 9 |
75 |
5 , @ : . - L P + |
76 |
6 / ^ = SHR HOM ; * £ |
77 |
7 R/S Q C= SPC 2 CTL <- 1 |
78 |
*/ |
79 |
|
80 |
#define MATRIX(a,b) (((a) << 3) | (b)) |
81 |
|
82 |
#define KEY_F9 512 |
83 |
#define KEY_F10 513 |
84 |
#define KEY_F11 514 |
85 |
#define KEY_F12 515 |
86 |
|
87 |
#ifdef SUN |
88 |
#define KEY_FIRE 58 |
89 |
#define KEY_JU 135 |
90 |
#define KEY_JD 7 |
91 |
#define KEY_JL 130 |
92 |
#define KEY_JR 2 |
93 |
#else |
94 |
#define KEY_FIRE 516 |
95 |
#define KEY_JU 517 |
96 |
#define KEY_JD 518 |
97 |
#define KEY_JL 519 |
98 |
#define KEY_JR 520 |
99 |
#endif |
100 |
|
101 |
#define KEY_JUL 521 |
102 |
#define KEY_JUR 522 |
103 |
#define KEY_JDL 523 |
104 |
#define KEY_JDR 524 |
105 |
|
106 |
#define KEY_KP_PLUS 525 |
107 |
#define KEY_KP_MINUS 526 |
108 |
#define KEY_KP_MULT 527 |
109 |
#define KEY_NUM_LOCK 528 |
110 |
|
111 |
|
112 |
/* |
113 |
* Decode KeySyms. This function knows about all keys that |
114 |
* are common between different keyboard languages. |
115 |
*/ |
116 |
|
117 |
static int kc_decode(KeySym ks) |
118 |
{ |
119 |
switch (ks) { |
120 |
case XK_A: case XK_a: return MATRIX(1,2); |
121 |
case XK_B: case XK_b: return MATRIX(3,4); |
122 |
case XK_C: case XK_c: return MATRIX(2,4); |
123 |
case XK_D: case XK_d: return MATRIX(2,2); |
124 |
case XK_E: case XK_e: return MATRIX(1,6); |
125 |
case XK_F: case XK_f: return MATRIX(2,5); |
126 |
case XK_G: case XK_g: return MATRIX(3,2); |
127 |
case XK_H: case XK_h: return MATRIX(3,5); |
128 |
case XK_I: case XK_i: return MATRIX(4,1); |
129 |
case XK_J: case XK_j: return MATRIX(4,2); |
130 |
case XK_K: case XK_k: return MATRIX(4,5); |
131 |
case XK_L: case XK_l: return MATRIX(5,2); |
132 |
case XK_M: case XK_m: return MATRIX(4,4); |
133 |
case XK_N: case XK_n: return MATRIX(4,7); |
134 |
case XK_O: case XK_o: return MATRIX(4,6); |
135 |
case XK_P: case XK_p: return MATRIX(5,1); |
136 |
case XK_Q: case XK_q: return MATRIX(7,6); |
137 |
case XK_R: case XK_r: return MATRIX(2,1); |
138 |
case XK_S: case XK_s: return MATRIX(1,5); |
139 |
case XK_T: case XK_t: return MATRIX(2,6); |
140 |
case XK_U: case XK_u: return MATRIX(3,6); |
141 |
case XK_V: case XK_v: return MATRIX(3,7); |
142 |
case XK_W: case XK_w: return MATRIX(1,1); |
143 |
case XK_X: case XK_x: return MATRIX(2,7); |
144 |
case XK_Y: case XK_y: return MATRIX(3,1); |
145 |
case XK_Z: case XK_z: return MATRIX(1,4); |
146 |
|
147 |
case XK_0: return MATRIX(4,3); |
148 |
case XK_1: return MATRIX(7,0); |
149 |
case XK_2: return MATRIX(7,3); |
150 |
case XK_3: return MATRIX(1,0); |
151 |
case XK_4: return MATRIX(1,3); |
152 |
case XK_5: return MATRIX(2,0); |
153 |
case XK_6: return MATRIX(2,3); |
154 |
case XK_7: return MATRIX(3,0); |
155 |
case XK_8: return MATRIX(3,3); |
156 |
case XK_9: return MATRIX(4,0); |
157 |
|
158 |
case XK_space: return MATRIX(7,4); |
159 |
case XK_grave: return MATRIX(7,1); |
160 |
case XK_backslash: return MATRIX(6,6); |
161 |
case XK_comma: return MATRIX(5,7); |
162 |
case XK_period: return MATRIX(5,4); |
163 |
|
164 |
case XK_Escape: return MATRIX(7,7); |
165 |
case XK_Return: return MATRIX(0,1); |
166 |
case XK_BackSpace: case XK_Delete: return MATRIX(0,0); |
167 |
case XK_Insert: return MATRIX(6,3); |
168 |
case XK_Home: case XK_Help: return MATRIX(6,3); |
169 |
case XK_End: return MATRIX(6,0); |
170 |
#ifdef __hpux |
171 |
case XK_Prior: return MATRIX(6,0); |
172 |
case XK_Next: return MATRIX(6,5); |
173 |
#else |
174 |
case XK_Page_Up: return MATRIX(6,0); |
175 |
case XK_Page_Down: return MATRIX(6,5); |
176 |
#endif |
177 |
case XK_Control_L: return MATRIX(7,2); |
178 |
case XK_Control_R: return MATRIX(7,5); |
179 |
case XK_Shift_L: return MATRIX(1,7); |
180 |
case XK_Shift_R: return MATRIX(6,4); |
181 |
case XK_Alt_L: return MATRIX(7,5); |
182 |
case XK_Alt_R: return MATRIX(7,5); |
183 |
|
184 |
case XK_Up: return MATRIX(0,7)| 0x80; |
185 |
case XK_Down: return MATRIX(0,7); |
186 |
case XK_Left: return MATRIX(0,2) | 0x80; |
187 |
case XK_Right: return MATRIX(0,2); |
188 |
|
189 |
case XK_F1: return MATRIX(0,4); |
190 |
case XK_F2: return MATRIX(0,4) | 0x80; |
191 |
case XK_F3: return MATRIX(0,5); |
192 |
case XK_F4: return MATRIX(0,5) | 0x80; |
193 |
case XK_F5: return MATRIX(0,6); |
194 |
case XK_F6: return MATRIX(0,6) | 0x80; |
195 |
case XK_F7: return MATRIX(0,3); |
196 |
case XK_F8: return MATRIX(0,3) | 0x80; |
197 |
|
198 |
case XK_F9: return KEY_F9; |
199 |
case XK_F10: return KEY_F10; |
200 |
case XK_F11: return KEY_F11; |
201 |
case XK_F12: return KEY_F12; |
202 |
|
203 |
/* You never know which Keysyms might be missing on some workstation |
204 |
* This #ifdef should be enough. */ |
205 |
#if defined(XK_KP_Prior) && defined(XK_KP_Left) && defined(XK_KP_Insert) && defined (XK_KP_End) |
206 |
case XK_KP_0: case XK_KP_Insert: return KEY_FIRE; |
207 |
case XK_KP_1: case XK_KP_End: return KEY_JDL; |
208 |
case XK_KP_2: case XK_KP_Down: return KEY_JD; |
209 |
case XK_KP_3: case XK_KP_Next: return KEY_JDR; |
210 |
case XK_KP_4: case XK_KP_Left: return KEY_JL; |
211 |
case XK_KP_5: case XK_KP_Begin: return KEY_FIRE; |
212 |
case XK_KP_6: case XK_KP_Right: return KEY_JR; |
213 |
case XK_KP_7: case XK_KP_Home: return KEY_JUL; |
214 |
case XK_KP_8: case XK_KP_Up: return KEY_JU; |
215 |
case XK_KP_9: case XK_KP_Prior: return KEY_JUR; |
216 |
#else |
217 |
case XK_KP_0: return KEY_FIRE; |
218 |
case XK_KP_1: return KEY_JDL; |
219 |
case XK_KP_2: return KEY_JD; |
220 |
case XK_KP_3: return KEY_JDR; |
221 |
case XK_KP_4: return KEY_JL; |
222 |
case XK_KP_5: return KEY_FIRE; |
223 |
case XK_KP_6: return KEY_JR; |
224 |
case XK_KP_7: return KEY_JUL; |
225 |
case XK_KP_8: return KEY_JU; |
226 |
case XK_KP_9: return KEY_JUR; |
227 |
#endif |
228 |
|
229 |
case XK_KP_Add: return KEY_KP_PLUS; |
230 |
case XK_KP_Subtract: return KEY_KP_MINUS; |
231 |
case XK_KP_Multiply: return KEY_KP_MULT; |
232 |
case XK_KP_Divide: return MATRIX(6,7); |
233 |
case XK_KP_Enter: return MATRIX(0,1); |
234 |
|
235 |
#ifdef SUN |
236 |
case XK_Num_Lock: return KEY_NUM_LOCK; |
237 |
#endif |
238 |
} |
239 |
return -1; |
240 |
} |
241 |
|
242 |
static int decode_us(KeySym ks) |
243 |
{ |
244 |
switch(ks) { /* US specific */ |
245 |
case XK_minus: return MATRIX(5,0); |
246 |
case XK_equal: return MATRIX(5,3); |
247 |
case XK_bracketleft: return MATRIX(5,6); |
248 |
case XK_bracketright: return MATRIX(6,1); |
249 |
case XK_semicolon: return MATRIX(5,5); |
250 |
case XK_apostrophe: return MATRIX(6,2); |
251 |
case XK_slash: return MATRIX(6,7); |
252 |
} |
253 |
|
254 |
return -1; |
255 |
} |
256 |
|
257 |
static int decode_de(KeySym ks) |
258 |
{ |
259 |
switch(ks) { /* DE specific */ |
260 |
case XK_ssharp: return MATRIX(5,0); |
261 |
case XK_apostrophe: return MATRIX(5,3); |
262 |
case XK_Udiaeresis: case XK_udiaeresis: return MATRIX(5,6); |
263 |
case XK_plus: return MATRIX(6,1); |
264 |
case XK_Odiaeresis: case XK_odiaeresis: return MATRIX(5,5); |
265 |
case XK_Adiaeresis: case XK_adiaeresis: return MATRIX(6,2); |
266 |
case XK_numbersign: return MATRIX(6,5); |
267 |
case XK_less: case XK_greater: return MATRIX(6,0); |
268 |
case XK_minus: return MATRIX(6,7); |
269 |
} |
270 |
|
271 |
return -1; |
272 |
} |
273 |
|
274 |
static int keycode2c64(XKeyEvent *event) |
275 |
{ |
276 |
KeySym ks; |
277 |
int as; |
278 |
int index = 0; |
279 |
|
280 |
do { |
281 |
ks = XLookupKeysym(event, index); |
282 |
as = kc_decode(ks); |
283 |
|
284 |
if (as == -1) |
285 |
as = KBD_LANG == 0 ? decode_us(ks) : decode_de(ks); |
286 |
if (as != -1) |
287 |
return as; |
288 |
index++; |
289 |
} while (ks != NoSymbol); |
290 |
|
291 |
return -1; |
292 |
} |
293 |
|
294 |
|
295 |
/* |
296 |
* Display constructor: Draw Speedometer/LEDs in window |
297 |
*/ |
298 |
|
299 |
C64Display::C64Display(C64 *the_c64) : TheC64(the_c64) |
300 |
{ |
301 |
int i; |
302 |
char str[16]; |
303 |
|
304 |
quit_requested = false; |
305 |
|
306 |
// LEDs off |
307 |
for (i=0; i<4; i++) |
308 |
led_state[i] = old_led_state[i] = LED_OFF; |
309 |
|
310 |
// Draw speedometer/LEDs |
311 |
led_gc = XCreateGC(display, mywin, 0, 0); |
312 |
XSetFont(display, led_gc, led_font); |
313 |
|
314 |
XSetForeground(display, led_gc, fill_gray.pixel); |
315 |
XFillRectangle(display, mywin, led_gc, 0, DISPLAY_Y, DISPLAY_X-1, 16); |
316 |
|
317 |
XSetForeground(display, led_gc, shine_gray.pixel); |
318 |
XDrawLine(display, mywin, led_gc, 0, DISPLAY_Y, DISPLAY_X-1, DISPLAY_Y); |
319 |
for (i=0; i<5; i++) |
320 |
XDrawLine(display, mywin, led_gc, DISPLAY_X*i/5, DISPLAY_Y, DISPLAY_X*i/5, DISPLAY_Y+14); |
321 |
for (i=2; i<6; i++) { |
322 |
XDrawLine(display, mywin, led_gc, DISPLAY_X*i/5-23, DISPLAY_Y+11, DISPLAY_X*i/5-9, DISPLAY_Y+11); |
323 |
XDrawLine(display, mywin, led_gc, DISPLAY_X*i/5-9, DISPLAY_Y+11, DISPLAY_X*i/5-9, DISPLAY_Y+5); |
324 |
} |
325 |
|
326 |
XSetForeground(display, led_gc, shadow_gray.pixel); |
327 |
XDrawLine(display, mywin, led_gc, 0, DISPLAY_Y+15, DISPLAY_X-1, DISPLAY_Y+15); |
328 |
for (i=1; i<6; i++) |
329 |
XDrawLine(display, mywin, led_gc, DISPLAY_X*i/5-1, DISPLAY_Y+1, DISPLAY_X*i/5-1, DISPLAY_Y+15); |
330 |
for (i=2; i<6; i++) { |
331 |
XDrawLine(display, mywin, led_gc, DISPLAY_X*i/5-24, DISPLAY_Y+11, DISPLAY_X*i/5-24, DISPLAY_Y+4); |
332 |
XDrawLine(display, mywin, led_gc, DISPLAY_X*i/5-24, DISPLAY_Y+4, DISPLAY_X*i/5-9, DISPLAY_Y+4); |
333 |
} |
334 |
|
335 |
for (i=0; i<4; i++) { |
336 |
sprintf(str, "Drive %d", i+8); |
337 |
XSetForeground(display, led_gc, black.pixel); |
338 |
XDrawString(display, mywin, led_gc, DISPLAY_X*(i+1)/5+8, DISPLAY_Y+12, str, strlen(str)); |
339 |
draw_led(i, LED_OFF); |
340 |
} |
341 |
|
342 |
// Start timer for LED error blinking |
343 |
c64_disp = this; |
344 |
pulse_sa.sa_handler = (void (*)(int))pulse_handler; |
345 |
pulse_sa.sa_flags = SA_RESTART; |
346 |
sigemptyset(&pulse_sa.sa_mask); |
347 |
sigaction(SIGALRM, &pulse_sa, NULL); |
348 |
pulse_tv.it_interval.tv_sec = 0; |
349 |
pulse_tv.it_interval.tv_usec = 400000; |
350 |
pulse_tv.it_value.tv_sec = 0; |
351 |
pulse_tv.it_value.tv_usec = 400000; |
352 |
setitimer(ITIMER_REAL, &pulse_tv, NULL); |
353 |
} |
354 |
|
355 |
|
356 |
/* |
357 |
* Display destructor |
358 |
*/ |
359 |
|
360 |
C64Display::~C64Display() |
361 |
{ |
362 |
XAutoRepeatOn(display); |
363 |
XSync(display, 0); |
364 |
} |
365 |
|
366 |
|
367 |
/* |
368 |
* Prefs may have changed |
369 |
*/ |
370 |
|
371 |
void C64Display::NewPrefs(Prefs *prefs) |
372 |
{ |
373 |
} |
374 |
|
375 |
|
376 |
/* |
377 |
* Connect to X server and open window |
378 |
*/ |
379 |
|
380 |
int init_graphics(void) |
381 |
{ |
382 |
int i; |
383 |
char *display_name = 0; |
384 |
XSetWindowAttributes wattr; |
385 |
XSizeHints *hints; |
386 |
XColor exact_color; |
387 |
int pixbytes; |
388 |
|
389 |
display = XOpenDisplay(display_name); |
390 |
if (display == 0) { |
391 |
fprintf(stderr, "Can't connect to X server %s\n", XDisplayName(display_name)); |
392 |
return 0; |
393 |
} |
394 |
|
395 |
screen = XDefaultScreen(display); |
396 |
rootwin = XRootWindow(display, screen); |
397 |
if (XMatchVisualInfo(display, screen, 8, PseudoColor, &visualInfo)) { |
398 |
/* for our HP boxes */ |
399 |
} else if (XMatchVisualInfo(display, screen, 8, GrayScale, &visualInfo)) { |
400 |
} else { |
401 |
fprintf(stderr, "Can't obtain appropriate X visual\n"); |
402 |
return 0; |
403 |
} |
404 |
|
405 |
vis = visualInfo.visual; |
406 |
bitdepth = visualInfo.depth; |
407 |
pixbytes = (bitdepth == 24 || bitdepth == 32 ? 4 : bitdepth == 12 || bitdepth == 16 ? 2 : 1); |
408 |
fprintf(stderr, "Using %d bit visual\n", bitdepth); |
409 |
|
410 |
hsize = (DISPLAY_X + 3) & ~3; |
411 |
|
412 |
#if defined(X_USE_SHM) |
413 |
img = XShmCreateImage(display, vis, bitdepth, ZPixmap, 0, &shminfo, |
414 |
hsize, DISPLAY_Y); |
415 |
|
416 |
shminfo.shmid = shmget(IPC_PRIVATE, DISPLAY_Y * img->bytes_per_line, |
417 |
IPC_CREAT | 0777); |
418 |
shminfo.shmaddr = img->data = bufmem = (char *)shmat(shminfo.shmid, 0, 0); |
419 |
shminfo.readOnly = False; |
420 |
XShmAttach(display, &shminfo); |
421 |
XSync(display,0); |
422 |
/* now deleting means making it temporary */ |
423 |
shmctl(shminfo.shmid, IPC_RMID, 0); |
424 |
#else |
425 |
bufmem = (char *)malloc(pixbytes * hsize * DISPLAY_Y); |
426 |
img = XCreateImage(display, vis, bitdepth, ZPixmap, 0, bufmem, hsize, DISPLAY_Y, 32, 0); |
427 |
#endif |
428 |
|
429 |
cmap = XCreateColormap(display, rootwin, vis, AllocNone); |
430 |
|
431 |
XParseColor(display, cmap, "#000000", &black); |
432 |
if (!XAllocColor(display, cmap, &black)) |
433 |
fprintf(stderr, "Whoops??\n"); |
434 |
|
435 |
wattr.event_mask = eventmask; |
436 |
wattr.background_pixel = black.pixel; |
437 |
wattr.backing_store = Always; |
438 |
wattr.backing_planes = bitdepth; |
439 |
wattr.border_pixmap = None; |
440 |
wattr.border_pixel = black.pixel; |
441 |
wattr.colormap = cmap; |
442 |
|
443 |
mywin = XCreateWindow(display, rootwin, 0, 0, DISPLAY_X, DISPLAY_Y + 16, 0, |
444 |
bitdepth, InputOutput, vis, |
445 |
CWEventMask|CWBackPixel|CWBorderPixel|CWBackingStore |
446 |
|CWBackingPlanes|CWColormap, |
447 |
&wattr); |
448 |
XMapWindow(display, mywin); |
449 |
XStoreName(display, mywin, "Frodo"); |
450 |
|
451 |
if ((hints = XAllocSizeHints()) != NULL) { |
452 |
hints->min_width = DISPLAY_X; |
453 |
hints->max_width = DISPLAY_X; |
454 |
hints->min_height = DISPLAY_Y + 16; |
455 |
hints->max_height = DISPLAY_Y + 16; |
456 |
hints->flags = PMinSize | PMaxSize; |
457 |
XSetWMNormalHints(display, mywin, hints); |
458 |
XFree((char *)hints); |
459 |
} |
460 |
|
461 |
black_gc = XCreateGC(display,mywin, 0, 0); |
462 |
XSetForeground(display, black_gc, black.pixel); |
463 |
|
464 |
// Allocate colors for speedometer/LEDs |
465 |
if (!XAllocNamedColor(display, cmap, "rgb:d0/d0/d0", &fill_gray, &exact_color)) |
466 |
return 0; |
467 |
if (!XAllocNamedColor(display, cmap, "rgb:e8/e8/e8", &shine_gray, &exact_color)) |
468 |
return 0; |
469 |
if (!XAllocNamedColor(display, cmap, "rgb:98/98/98", &shadow_gray, &exact_color)) |
470 |
return 0; |
471 |
if (!XAllocNamedColor(display, cmap, "rgb:f0/00/00", &red, &exact_color)) |
472 |
return 0; |
473 |
if (!XAllocNamedColor(display, cmap, "rgb:00/f0/00", &green, &exact_color)) |
474 |
return 0; |
475 |
|
476 |
// Load font for speedometer/LED labels |
477 |
led_font = XLoadFont(display, "-*-helvetica-medium-r-*-*-10-*"); |
478 |
|
479 |
for(i=0; i<256; i++) |
480 |
keystate[i] = 0; |
481 |
|
482 |
return 1; |
483 |
} |
484 |
|
485 |
|
486 |
/* |
487 |
* Redraw bitmap |
488 |
*/ |
489 |
|
490 |
void C64Display::Update(void) |
491 |
{ |
492 |
// Update C64 display |
493 |
XSync(display, 0); |
494 |
#if defined(X_USE_SHM) |
495 |
XShmPutImage(display, mywin, black_gc, img, 0, 0, 0, 0, DISPLAY_X, DISPLAY_Y, 0); |
496 |
#else |
497 |
XPutImage(display, mywin, black_gc, img, 0, 0, 0, 0, DISPLAY_X, DISPLAY_Y); |
498 |
#endif |
499 |
|
500 |
// Update drive LEDs |
501 |
for (int i=0; i<4; i++) |
502 |
if (led_state[i] != old_led_state[i]) { |
503 |
draw_led(i, led_state[i]); |
504 |
old_led_state[i] = led_state[i]; |
505 |
} |
506 |
} |
507 |
|
508 |
|
509 |
/* |
510 |
* Draw one drive LED |
511 |
*/ |
512 |
|
513 |
void C64Display::draw_led(int num, int state) |
514 |
{ |
515 |
switch (state) { |
516 |
case LED_OFF: |
517 |
case LED_ERROR_OFF: |
518 |
XSetForeground(display, led_gc, black.pixel); |
519 |
break; |
520 |
case LED_ON: |
521 |
XSetForeground(display, led_gc, green.pixel); |
522 |
break; |
523 |
case LED_ERROR_ON: |
524 |
XSetForeground(display, led_gc, red.pixel); |
525 |
break; |
526 |
} |
527 |
XFillRectangle(display, mywin, led_gc, DISPLAY_X*(num+2)/5-23, DISPLAY_Y+5, 14, 6); |
528 |
} |
529 |
|
530 |
|
531 |
/* |
532 |
* LED error blink |
533 |
*/ |
534 |
|
535 |
void C64Display::pulse_handler(...) |
536 |
{ |
537 |
for (int i=0; i<4; i++) |
538 |
switch (c64_disp->led_state[i]) { |
539 |
case LED_ERROR_ON: |
540 |
c64_disp->led_state[i] = LED_ERROR_OFF; |
541 |
break; |
542 |
case LED_ERROR_OFF: |
543 |
c64_disp->led_state[i] = LED_ERROR_ON; |
544 |
break; |
545 |
} |
546 |
} |
547 |
|
548 |
|
549 |
/* |
550 |
* Draw speedometer |
551 |
*/ |
552 |
|
553 |
void C64Display::Speedometer(int speed) |
554 |
{ |
555 |
static int delay = 0; |
556 |
|
557 |
if (delay >= 20) { |
558 |
char str[16]; |
559 |
sprintf(str, "%d%%", speed); |
560 |
XSetForeground(display, led_gc, fill_gray.pixel); |
561 |
XFillRectangle(display,mywin, led_gc, 1, DISPLAY_Y+1, DISPLAY_X/5-2, 14); |
562 |
XSetForeground(display, led_gc, black.pixel); |
563 |
XDrawString(display, mywin, led_gc, 24, DISPLAY_Y+12, str, strlen(str)); |
564 |
delay = 0; |
565 |
} else |
566 |
delay++; |
567 |
} |
568 |
|
569 |
|
570 |
/* |
571 |
* Return pointer to bitmap data |
572 |
*/ |
573 |
|
574 |
uint8 *C64Display::BitmapBase(void) |
575 |
{ |
576 |
return (uint8 *)bufmem; |
577 |
} |
578 |
|
579 |
|
580 |
/* |
581 |
* Return number of bytes per row |
582 |
*/ |
583 |
|
584 |
int C64Display::BitmapXMod(void) |
585 |
{ |
586 |
return hsize; |
587 |
} |
588 |
|
589 |
|
590 |
/* |
591 |
* Poll the keyboard |
592 |
*/ |
593 |
|
594 |
void C64Display::PollKeyboard(uint8 *key_matrix, uint8 *rev_matrix, uint8 *joystick) |
595 |
{ |
596 |
static bool auto_rep = true; |
597 |
for(;;) { |
598 |
XEvent event; |
599 |
if (!XCheckMaskEvent(display, eventmask, &event)) |
600 |
break; |
601 |
|
602 |
switch(event.type) { |
603 |
|
604 |
case KeyPress: { |
605 |
int kc = keycode2c64((XKeyEvent *)&event); |
606 |
if (kc == -1) |
607 |
break; |
608 |
switch (kc) { |
609 |
|
610 |
case KEY_F9: // F9: Invoke SAM |
611 |
SAM(TheC64); |
612 |
break; |
613 |
|
614 |
case KEY_F10: // F10: Quit |
615 |
quit_requested = true; |
616 |
break; |
617 |
|
618 |
case KEY_F11: // F11: NMI (Restore) |
619 |
TheC64->NMI(); |
620 |
break; |
621 |
|
622 |
case KEY_F12: // F12: Reset |
623 |
TheC64->Reset(); |
624 |
break; |
625 |
|
626 |
case KEY_NUM_LOCK: // NumLock: Toggle joyport |
627 |
num_locked = true; |
628 |
break; |
629 |
|
630 |
case KEY_FIRE: |
631 |
joystate &= ~0x10; |
632 |
break; |
633 |
case KEY_JD: |
634 |
joystate &= ~0x02; |
635 |
break; |
636 |
case KEY_JU: |
637 |
joystate &= ~0x01; |
638 |
break; |
639 |
case KEY_JL: |
640 |
joystate &= ~0x04; |
641 |
break; |
642 |
case KEY_JR: |
643 |
joystate &= ~0x08; |
644 |
break; |
645 |
case KEY_JUL: |
646 |
joystate &= ~0x05; |
647 |
break; |
648 |
case KEY_JUR: |
649 |
joystate &= ~0x09; |
650 |
break; |
651 |
case KEY_JDL: |
652 |
joystate &= ~0x06; |
653 |
break; |
654 |
case KEY_JDR: |
655 |
joystate &= ~0x0a; |
656 |
break; |
657 |
|
658 |
case KEY_KP_PLUS: // '+' on keypad: Increase SkipFrames |
659 |
ThePrefs.SkipFrames++; |
660 |
break; |
661 |
|
662 |
case KEY_KP_MINUS: // '-' on keypad: Decrease SkipFrames |
663 |
if (ThePrefs.SkipFrames > 1) |
664 |
ThePrefs.SkipFrames--; |
665 |
break; |
666 |
|
667 |
case KEY_KP_MULT: // '*' on keypad: Toggle speed limiter |
668 |
ThePrefs.LimitSpeed = !ThePrefs.LimitSpeed; |
669 |
break; |
670 |
|
671 |
default: |
672 |
if (keystate[kc]) |
673 |
break; |
674 |
keystate[kc] = 1; |
675 |
int c64_byte, c64_bit, shifted; |
676 |
c64_byte = kc >> 3; |
677 |
c64_bit = kc & 7; |
678 |
shifted = kc & 128; |
679 |
c64_byte &= 7; |
680 |
if (shifted) { |
681 |
key_matrix[6] &= 0xef; |
682 |
rev_matrix[4] &= 0xbf; |
683 |
} |
684 |
key_matrix[c64_byte] &= ~(1 << c64_bit); |
685 |
rev_matrix[c64_bit] &= ~(1 << c64_byte); |
686 |
break; |
687 |
} |
688 |
break; |
689 |
} |
690 |
|
691 |
case KeyRelease: { |
692 |
int kc = keycode2c64((XKeyEvent *)&event); |
693 |
if (kc == -1) |
694 |
break; |
695 |
switch (kc) { |
696 |
|
697 |
case KEY_NUM_LOCK: |
698 |
num_locked = false; |
699 |
break; |
700 |
|
701 |
case KEY_FIRE: |
702 |
joystate |= 0x10; |
703 |
break; |
704 |
case KEY_JD: |
705 |
joystate |= 0x02; |
706 |
break; |
707 |
case KEY_JU: |
708 |
joystate |= 0x01; |
709 |
break; |
710 |
case KEY_JL: |
711 |
joystate |= 0x04; |
712 |
break; |
713 |
case KEY_JR: |
714 |
joystate |= 0x08; |
715 |
break; |
716 |
case KEY_JUL: |
717 |
joystate |= 0x05; |
718 |
break; |
719 |
case KEY_JUR: |
720 |
joystate |= 0x09; |
721 |
break; |
722 |
case KEY_JDL: |
723 |
joystate |= 0x06; |
724 |
break; |
725 |
case KEY_JDR: |
726 |
joystate |= 0x0a; |
727 |
break; |
728 |
|
729 |
default: |
730 |
if (!keystate[kc]) |
731 |
break; |
732 |
keystate[kc] = 0; |
733 |
int c64_byte, c64_bit, shifted; |
734 |
c64_byte = kc >> 3; |
735 |
c64_bit = kc & 7; |
736 |
shifted = kc & 128; |
737 |
c64_byte &= 7; |
738 |
if (shifted) { |
739 |
key_matrix[6] |= 0x10; |
740 |
rev_matrix[4] |= 0x40; |
741 |
} |
742 |
key_matrix[c64_byte] |= (1 << c64_bit); |
743 |
rev_matrix[c64_bit] |= (1 << c64_byte); |
744 |
break; |
745 |
} |
746 |
} |
747 |
|
748 |
case FocusIn: |
749 |
if (auto_rep) { |
750 |
XAutoRepeatOff(display); |
751 |
auto_rep = false; |
752 |
} |
753 |
break; |
754 |
|
755 |
case FocusOut: |
756 |
if (!auto_rep) { |
757 |
XAutoRepeatOn(display); |
758 |
auto_rep = true; |
759 |
} |
760 |
break; |
761 |
} |
762 |
} |
763 |
*joystick = joystate; |
764 |
} |
765 |
|
766 |
|
767 |
/* |
768 |
* Check if NumLock is down (for switching the joystick keyboard emulation) |
769 |
*/ |
770 |
|
771 |
bool C64Display::NumLock(void) |
772 |
{ |
773 |
return num_locked; |
774 |
} |
775 |
|
776 |
|
777 |
/* |
778 |
* Open/close joystick drivers given old and new state of |
779 |
* joystick preferences |
780 |
*/ |
781 |
|
782 |
void C64::open_close_joysticks(int oldjoy1, int oldjoy2, int newjoy1, int newjoy2) |
783 |
{ |
784 |
} |
785 |
|
786 |
|
787 |
/* |
788 |
* Poll joystick port, return CIA mask |
789 |
*/ |
790 |
|
791 |
uint8 C64::poll_joystick(int port) |
792 |
{ |
793 |
return 0xff; |
794 |
} |
795 |
|
796 |
|
797 |
/* |
798 |
* Allocate C64 colors |
799 |
*/ |
800 |
|
801 |
void C64Display::InitColors(uint8 *colors) |
802 |
{ |
803 |
int i; |
804 |
XColor col; |
805 |
char str[20]; |
806 |
|
807 |
for (i=0; i< 256; i++) { |
808 |
sprintf(str, "rgb:%x/%x/%x", palette_red[i & 0x0f], palette_green[i & 0x0f], palette_blue[i & 0x0f]); |
809 |
XParseColor(display, cmap, str, &col); |
810 |
if (XAllocColor(display, cmap, &col)) |
811 |
colors[i] = col.pixel; |
812 |
else |
813 |
fprintf(stderr, "Couldn't get all colors\n"); |
814 |
} |
815 |
} |
816 |
|
817 |
|
818 |
/* |
819 |
* Show a requester (error message) |
820 |
*/ |
821 |
|
822 |
long int ShowRequester(char *a,char *b,char *) |
823 |
{ |
824 |
printf("%s: %s\n", a, b); |
825 |
return 1; |
826 |
} |