1 /*
2  * atari_x11.c - X11 specific port code
3  *
4  * Copyright (c) 1995-1998 David Firth
5  * Copyright (C) 1998-2014 Atari800 development team (see DOC/CREDITS)
6  *
7  * This file is part of the Atari800 emulator project which emulates
8  * the Atari 400, 800, 800XL, 130XE, and 5200 8-bit computers.
9  *
10  * Atari800 is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * Atari800 is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Atari800; if not, write to the Free Software
22  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
23 */
24 
25 #include "config.h"
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <unistd.h>
30 #include <fcntl.h>
31 #include "pokey.h"
32 
33 #ifdef VMS
34 #include <stat.h>
35 #else
36 #include <sys/stat.h>
37 #endif
38 
39 #include <signal.h>
40 #include <sys/time.h>
41 
42 typedef unsigned char ubyte;
43 typedef unsigned short uword;
44 
45 #ifdef XVIEW
46 #include <xview/xview.h>
47 #include <xview/frame.h>
48 #include <xview/panel.h>
49 #include <xview/canvas.h>
50 #include <xview/notice.h>
51 #include <xview/file_chsr.h>
52 #endif
53 
54 #ifdef MOTIF
55 #include <Xm/MainW.h>
56 #include <Xm/DrawingA.h>
57 #include <Xm/MessageB.h>
58 #include <Xm/FileSB.h>
59 #include <Xm/RowColumn.h>
60 #include <Xm/ToggleBG.h>
61 
62 static XtAppContext app;
63 static Widget toplevel;
64 static Widget main_w;
65 static Widget drawing_area;
66 static Widget fsel_b;
67 static Widget fsel_d;
68 static Widget fsel_r;
69 static Widget rbox_d;
70 static Widget togg_d1, togg_d2, togg_d3, togg_d4;
71 static Widget togg_d5, togg_d6, togg_d7, togg_d8;
72 static Widget eject_menu;
73 static Widget disable_menu;
74 static Widget system_menu;
75 static int motif_disk_sel = 1;
76 #endif /* MOTIF */
77 
78 #include <X11/Xlib.h>
79 #include <X11/Xutil.h>
80 #include <X11/keysym.h>
81 
82 #include "atari.h"
83 #include "cartridge.h"
84 #include "colours.h"
85 #include "input.h"
86 #include "akey.h"
87 #include "log.h"
88 #include "monitor.h"
89 #include "memory.h"
90 #include "screen.h"
91 #include "sio.h"
92 #include "sound.h"
93 #include "platform.h"
94 #include "ui.h"
95 #include "util.h"
96 
97 #ifdef SHM
98 #include <sys/ipc.h>
99 #include <sys/shm.h>
100 #include <X11/extensions/XShm.h>
101 
102 static XShmSegmentInfo shminfo;
103 static XImage *image = NULL;
104 #ifdef USE_COLOUR_TRANSLATION_TABLE
105 extern int colour_translation_table[256];
106 #endif
107 #endif /* SHM */
108 
109 static int invisible = 0;
110 
111 #ifdef LINUX_JOYSTICK
112 #include <linux/joystick.h>
113 
114 static int js0;
115 static int js1;
116 
117 static int js0_centre_x;
118 static int js0_centre_y;
119 static int js1_centre_x;
120 static int js1_centre_y;
121 
122 static struct JS_DATA_TYPE js_data;
123 #endif /* LINUX_JOYSTICK */
124 
125 typedef enum {
126 	Small,
127 	Large,
128 	Huge
129 } WindowSize;
130 
131 static WindowSize windowsize = Large;
132 
133 enum {
134 	MONITOR_NOTHING,
135 	MONITOR_SIO
136 } x11_monitor = MONITOR_NOTHING;
137 
138 static int x11bug = FALSE;
139 static int private_cmap = FALSE;
140 
141 static int window_width = 336;
142 static int window_height = Screen_HEIGHT;
143 
144 static int clipping_factor = 1;
145 static int clipping_x = 24;
146 static int clipping_y = 0;
147 static int clipping_width = 336;
148 static int clipping_height = Screen_HEIGHT;
149 
150 
151 static Display *display = NULL;
152 static Screen *screen = NULL;
153 static Window window;
154 #ifndef SHM
155 static Pixmap pixmap;
156 #endif
157 static Visual *visual = NULL;
158 static Colormap cmap;
159 
160 static GC gc;
161 static GC gc_colour[256];
162 static int colours[256];
163 
164 #ifdef XVIEW
165 static Frame frame;
166 static Panel panel;
167 static Canvas canvas;
168 static Menu system_menu;
169 static Menu consol_menu;
170 static Menu options_menu;
171 static Frame chooser;
172 
173 static Frame controllers_frame;
174 static Panel controllers_panel;
175 static Panel_item keypad_item;
176 static Panel_item mouse_item;
177 
178 #ifdef LINUX_JOYSTICK
179 static Panel_item js0_item;
180 static Panel_item js1_item;
181 #endif
182 
183 static Frame performance_frame;
184 static Panel performance_panel;
185 static Panel_item refresh_slider;
186 #endif /* XVIEW */
187 
188 static int SHIFT = 0x00;
189 static int CONTROL = 0x00;
190 static UBYTE *image_data = NULL;
191 static int modified;
192 
193 static int keypad_mode = -1;	/* Joystick */
194 static int keypad_trig = 1;		/* Keypad Trigger Position */
195 static int keypad_stick = 0x0f;	/* Keypad Joystick Position */
196 
197 static int xmouse_mode = -1;		/* Joystick, Paddle and Light Pen */
198 static int mouse_stick;			/* Mouse Joystick Position */
199 
200 static int js0_mode = -1;
201 static int js1_mode = -1;
202 
203 #ifndef SHM
204 
205 #define	NPOINTS	(4096 / 4)
206 #define	NRECTS	(4096 / 4)
207 
208 static XPoint points[NPOINTS];
209 static XRectangle rectangles[NRECTS];
210 #endif
211 
212 static int keyboard_consol = INPUT_CONSOL_NONE;
213 static int menu_consol = INPUT_CONSOL_NONE;
214 
215 static int autorepeat = 1;
216 static int last_focus = FocusOut;
217 
autorepeat_get(void)218 static void autorepeat_get(void)
219 {
220 	XKeyboardState kstat;
221 
222 	XGetKeyboardControl(display, &kstat);
223 	autorepeat = kstat.global_auto_repeat;
224 }
225 
autorepeat_off(void)226 static void autorepeat_off(void)
227 {
228 	XAutoRepeatOff(display);
229 }
230 
autorepeat_restore(void)231 static void autorepeat_restore(void)
232 {
233 	if (autorepeat)
234 		XAutoRepeatOn(display);
235 	else
236 		XAutoRepeatOff(display);
237 }
238 
segmentationfault(int x)239 static void segmentationfault(int x)
240 {
241 	Atari800_ErrExit();
242 	exit(0);
243 }
244 
GetKeyCode(XEvent * event)245 static int GetKeyCode(XEvent *event)
246 {
247 	KeySym keysym;
248 	char buffer[128];
249 	static int keycode = AKEY_NONE;
250 
251 	if (event->type == KeyPress || event->type == KeyRelease) {
252 		XLookupString((XKeyEvent *) event, buffer, sizeof(buffer), &keysym, NULL);
253 	}
254 
255 	switch (event->type) {
256 	case Expose:
257 #ifndef SHM
258 		XCopyArea(display, pixmap, window, gc,
259 				  0, 0,
260 				  window_width, window_height,
261 				  0, 0);
262 #else
263 		modified = TRUE;
264 #endif
265 		break;
266 	case FocusIn:
267 		autorepeat_off();
268 		last_focus = FocusIn;
269 		break;
270 	case FocusOut:
271 		autorepeat_restore();
272 		last_focus = FocusOut;
273 		break;
274 	case VisibilityNotify:
275 		if (((XVisibilityEvent*) event)->state == VisibilityFullyObscured)
276 			invisible = 1;
277 		else
278 			invisible = 0;
279 		break;
280 	case KeyPress:
281 		switch (keysym) {
282 		case XK_Shift_L:
283 		case XK_Shift_R:
284 			SHIFT = AKEY_SHFT;
285 			INPUT_key_shift = 1;
286 			break;
287 		case XK_Control_L:
288 			keypad_trig = 0;
289 			/* FALLTHROUGH */
290 		case XK_Control_R:
291 			CONTROL = AKEY_CTRL;
292 			break;
293 		case XK_F1:
294 			keycode = AKEY_UI;
295 			break;
296 		case XK_F5:
297 		case XK_L5:
298 			keycode = SHIFT ? AKEY_COLDSTART : AKEY_WARMSTART;
299 			break;
300 		case XK_F8:
301 			keycode = PLATFORM_Exit(TRUE) ? AKEY_NONE : AKEY_EXIT;
302 			break;
303 		case XK_F9:
304 			keycode = AKEY_EXIT;
305 			break;
306 		case XK_F10:
307 		case XK_L10:
308 			keycode = SHIFT ? AKEY_SCREENSHOT_INTERLACE : AKEY_SCREENSHOT;
309 			break;
310 		case XK_F12:
311 			keycode = AKEY_TURBO;
312 			break;
313 		case XK_Left:
314 			keycode = AKEY_LEFT;
315 			keypad_stick &= INPUT_STICK_LEFT;
316 			break;
317 		case XK_Up:
318 			keycode = AKEY_UP;
319 			keypad_stick &= INPUT_STICK_FORWARD;
320 			break;
321 		case XK_Right:
322 			keycode = AKEY_RIGHT;
323 			keypad_stick &= INPUT_STICK_RIGHT;
324 			break;
325 		case XK_Down:
326 			keycode = AKEY_DOWN;
327 			keypad_stick &= INPUT_STICK_BACK;
328 			break;
329 		case XK_KP_0:
330 			keypad_trig = 0;
331 			keycode = AKEY_NONE;
332 			break;
333 		case XK_KP_1:
334 			keypad_stick = INPUT_STICK_LL;
335 			keycode = AKEY_NONE;
336 			break;
337 		case XK_KP_2:
338 			keypad_stick &= INPUT_STICK_BACK;
339 			keycode = AKEY_NONE;
340 			break;
341 		case XK_KP_3:
342 			keypad_stick = INPUT_STICK_LR;
343 			keycode = AKEY_NONE;
344 			break;
345 		case XK_KP_4:
346 			keypad_stick &= INPUT_STICK_LEFT;
347 			keycode = AKEY_NONE;
348 			break;
349 		case XK_KP_5:
350 			keypad_stick = INPUT_STICK_CENTRE;
351 			keycode = AKEY_NONE;
352 			break;
353 		case XK_KP_6:
354 			keypad_stick &= INPUT_STICK_RIGHT;
355 			keycode = AKEY_NONE;
356 			break;
357 		case XK_KP_7:
358 			keypad_stick = INPUT_STICK_UL;
359 			keycode = AKEY_NONE;
360 			break;
361 		case XK_KP_8:
362 			keypad_stick &= INPUT_STICK_FORWARD;
363 			keycode = AKEY_NONE;
364 			break;
365 		case XK_KP_9:
366 			keypad_stick = INPUT_STICK_UR;
367 			keycode = AKEY_NONE;
368 			break;
369 		}
370 		if (Atari800_machine_type == Atari800_MACHINE_5200 && !UI_is_active) {
371 			switch (keysym) {
372 			case XK_F4:
373 				keycode = SHIFT | AKEY_5200_START;
374 				break;
375 			case XK_P:
376 			case XK_p:
377 				keycode = SHIFT | AKEY_5200_PAUSE;
378 				break;
379 			case XK_R:
380 			case XK_r:
381 				keycode = SHIFT | AKEY_5200_RESET;
382 				break;
383 			case XK_0:
384 				keycode = SHIFT | AKEY_5200_0;
385 				break;
386 			case XK_1:
387 				keycode = SHIFT | AKEY_5200_1;
388 				break;
389 			case XK_2:
390 				keycode = SHIFT | AKEY_5200_2;
391 				break;
392 			case XK_3:
393 				keycode = SHIFT | AKEY_5200_3;
394 				break;
395 			case XK_4:
396 				keycode = SHIFT | AKEY_5200_4;
397 				break;
398 			case XK_5:
399 				keycode = SHIFT | AKEY_5200_5;
400 				break;
401 			case XK_6:
402 				keycode = SHIFT | AKEY_5200_6;
403 				break;
404 			case XK_7:
405 				keycode = SHIFT | AKEY_5200_7;
406 				break;
407 			case XK_8:
408 				keycode = SHIFT | AKEY_5200_8;
409 				break;
410 			case XK_9:
411 				keycode = SHIFT | AKEY_5200_9;
412 				break;
413 			/* XXX: "SHIFT | " harmful for '#' and '*' ? */
414 			case XK_numbersign:
415 			case XK_equal:
416 				keycode = AKEY_5200_HASH;
417 				break;
418 			case XK_asterisk:
419 				keycode = AKEY_5200_ASTERISK;
420 				break;
421 			}
422 			break;
423 		}
424 		switch (keysym) {
425 		case XK_Caps_Lock:
426 			keycode = SHIFT | CONTROL | AKEY_CAPSTOGGLE;
427 			break;
428 		case XK_Shift_Lock:
429 			if (x11bug)
430 				printf("XK_Shift_Lock\n");
431 			break;
432 		case XK_Alt_L:
433 		case XK_Alt_R:
434 			keycode = AKEY_ATARI;
435 			break;
436 		case XK_F2:
437 			keyboard_consol &= (~INPUT_CONSOL_OPTION);
438 			keycode = AKEY_NONE;
439 			break;
440 		case XK_F3:
441 			keyboard_consol &= (~INPUT_CONSOL_SELECT);
442 			keycode = AKEY_NONE;
443 			break;
444 		case XK_F4:
445 			keyboard_consol &= (~INPUT_CONSOL_START);
446 			keycode = AKEY_NONE;
447 			break;
448 		case XK_F6:
449 			keycode = SHIFT | CONTROL | AKEY_HELP;
450 			break;
451 		case XK_Break:
452 		case XK_F7:
453 			keycode = AKEY_BREAK;
454 			break;
455 		case XK_Home:
456 			keycode = AKEY_CLEAR;
457 			break;
458 		case XK_Insert:
459 			if (SHIFT)
460 				keycode = AKEY_INSERT_LINE;
461 			else
462 				keycode = AKEY_INSERT_CHAR;
463 			break;
464 		case XK_BackSpace:
465 			if (CONTROL)
466 				keycode = AKEY_DELETE_CHAR;
467 			else if (SHIFT)
468 				keycode = AKEY_DELETE_LINE;
469 			else
470 				keycode = AKEY_BACKSPACE;
471 			break;
472 		case XK_Delete:
473 			if (CONTROL)
474 				keycode = AKEY_DELETE_CHAR;
475 			else if (SHIFT)
476 				keycode = AKEY_DELETE_LINE;
477 			else
478 				keycode = AKEY_BACKSPACE; /* XXX */
479 			break;
480 		case XK_End:
481 			keycode = SHIFT | CONTROL | AKEY_HELP;
482 			break;
483 		case XK_Escape:
484 			keycode = SHIFT | CONTROL | AKEY_ESCAPE;
485 			break;
486 		case XK_Tab:
487 			keycode = SHIFT | CONTROL | AKEY_TAB;
488 			break;
489 		case XK_exclam:
490 			keycode = CONTROL | AKEY_EXCLAMATION;
491 			break;
492 		case XK_quotedbl:
493 			keycode = CONTROL | AKEY_DBLQUOTE;
494 			break;
495 		case XK_numbersign:
496 			keycode = CONTROL | AKEY_HASH;
497 			break;
498 		case XK_dollar:
499 			keycode = CONTROL | AKEY_DOLLAR;
500 			break;
501 		case XK_percent:
502 			keycode = CONTROL | AKEY_PERCENT;
503 			break;
504 		case XK_ampersand:
505 			keycode = CONTROL | AKEY_AMPERSAND;
506 			break;
507 		case XK_quoteright:
508 			keycode = CONTROL | AKEY_QUOTE;
509 			break;
510 		case XK_at:
511 			keycode = CONTROL | AKEY_AT;
512 			break;
513 		case XK_parenleft:
514 			keycode = CONTROL | AKEY_PARENLEFT;
515 			break;
516 		case XK_parenright:
517 			keycode = CONTROL | AKEY_PARENRIGHT;
518 			break;
519 		case XK_less:
520 			keycode = CONTROL | AKEY_LESS;
521 			break;
522 		case XK_greater:
523 			keycode = CONTROL | AKEY_GREATER;
524 			break;
525 		case XK_equal:
526 			keycode = CONTROL | AKEY_EQUAL;
527 			break;
528 		case XK_question:
529 			keycode = CONTROL | AKEY_QUESTION;
530 			break;
531 		case XK_minus:
532 			keycode = CONTROL | AKEY_MINUS;
533 			break;
534 		case XK_plus:
535 			keycode = CONTROL | AKEY_PLUS;
536 			break;
537 		case XK_asterisk:
538 			keycode = CONTROL | AKEY_ASTERISK;
539 			break;
540 		case XK_slash:
541 			keycode = CONTROL | AKEY_SLASH;
542 			break;
543 		case XK_colon:
544 			keycode = CONTROL | AKEY_COLON;
545 			break;
546 		case XK_semicolon:
547 			keycode = CONTROL | AKEY_SEMICOLON;
548 			break;
549 		case XK_comma:
550 			keycode = CONTROL | AKEY_COMMA;
551 			break;
552 		case XK_period:
553 			keycode = CONTROL | AKEY_FULLSTOP;
554 			break;
555 		case XK_underscore:
556 			keycode = CONTROL | AKEY_UNDERSCORE;
557 			break;
558 		case XK_bracketleft:
559 			keycode = CONTROL | AKEY_BRACKETLEFT;
560 			break;
561 		case XK_bracketright:
562 			keycode = CONTROL | AKEY_BRACKETRIGHT;
563 			break;
564 		case XK_asciicircum:
565 			keycode = CONTROL | AKEY_CIRCUMFLEX;
566 			break;
567 		case XK_backslash:
568 			keycode = CONTROL | AKEY_BACKSLASH;
569 			break;
570 		case XK_bar:
571 			keycode = CONTROL | AKEY_BAR;
572 			break;
573 		case XK_space:
574 			keycode = SHIFT | CONTROL | AKEY_SPACE;
575 			keypad_trig = 0;
576 			break;
577 		case XK_Return:
578 			keycode = SHIFT | CONTROL | AKEY_RETURN;
579 			keypad_stick = INPUT_STICK_CENTRE;
580 			break;
581 		case XK_0:
582 			keycode = CONTROL | AKEY_0;
583 			break;
584 		case XK_1:
585 			keycode = CONTROL | AKEY_1;
586 			break;
587 		case XK_2:
588 			keycode = CONTROL | AKEY_2;
589 			break;
590 		case XK_3:
591 			keycode = CONTROL | AKEY_3;
592 			break;
593 		case XK_4:
594 			keycode = CONTROL | AKEY_4;
595 			break;
596 		case XK_5:
597 			keycode = CONTROL | AKEY_5;
598 			break;
599 		case XK_6:
600 			keycode = CONTROL | AKEY_6;
601 			break;
602 		case XK_7:
603 			keycode = CONTROL | AKEY_7;
604 			break;
605 		case XK_8:
606 			keycode = CONTROL | AKEY_8;
607 			break;
608 		case XK_9:
609 			keycode = CONTROL | AKEY_9;
610 			break;
611 		case XK_A:
612 		case XK_a:
613 			keycode = SHIFT | CONTROL | AKEY_a;
614 			break;
615 		case XK_B:
616 		case XK_b:
617 			keycode = SHIFT | CONTROL | AKEY_b;
618 			break;
619 		case XK_C:
620 		case XK_c:
621 			keycode = SHIFT | CONTROL | AKEY_c;
622 			break;
623 		case XK_D:
624 		case XK_d:
625 			keycode = SHIFT | CONTROL | AKEY_d;
626 			break;
627 		case XK_E:
628 		case XK_e:
629 			keycode = SHIFT | CONTROL | AKEY_e;
630 			break;
631 		case XK_F:
632 		case XK_f:
633 			keycode = SHIFT | CONTROL | AKEY_f;
634 			break;
635 		case XK_G:
636 		case XK_g:
637 			keycode = SHIFT | CONTROL | AKEY_g;
638 			break;
639 		case XK_H:
640 		case XK_h:
641 			keycode = SHIFT | CONTROL | AKEY_h;
642 			break;
643 		case XK_I:
644 		case XK_i:
645 			keycode = SHIFT | CONTROL | AKEY_i;
646 			break;
647 		case XK_J:
648 		case XK_j:
649 			keycode = SHIFT | CONTROL | AKEY_j;
650 			break;
651 		case XK_K:
652 		case XK_k:
653 			keycode = SHIFT | CONTROL | AKEY_k;
654 			break;
655 		case XK_L:
656 		case XK_l:
657 			keycode = SHIFT | CONTROL | AKEY_l;
658 			break;
659 		case XK_M:
660 		case XK_m:
661 			keycode = SHIFT | CONTROL | AKEY_m;
662 			break;
663 		case XK_N:
664 		case XK_n:
665 			keycode = SHIFT | CONTROL | AKEY_n;
666 			break;
667 		case XK_O:
668 		case XK_o:
669 			keycode = SHIFT | CONTROL | AKEY_o;
670 			break;
671 		case XK_P:
672 		case XK_p:
673 			keycode = SHIFT | CONTROL | AKEY_p;
674 			break;
675 		case XK_Q:
676 		case XK_q:
677 			keycode = SHIFT | CONTROL | AKEY_q;
678 			break;
679 		case XK_R:
680 		case XK_r:
681 			keycode = SHIFT | CONTROL | AKEY_r;
682 			break;
683 		case XK_S:
684 		case XK_s:
685 			keycode = SHIFT | CONTROL | AKEY_s;
686 			break;
687 		case XK_T:
688 		case XK_t:
689 			keycode = SHIFT | CONTROL | AKEY_t;
690 			break;
691 		case XK_U:
692 		case XK_u:
693 			keycode = SHIFT | CONTROL | AKEY_u;
694 			break;
695 		case XK_V:
696 		case XK_v:
697 			keycode = SHIFT | CONTROL | AKEY_v;
698 			break;
699 		case XK_W:
700 		case XK_w:
701 			keycode = SHIFT | CONTROL | AKEY_w;
702 			break;
703 		case XK_X:
704 		case XK_x:
705 			keycode = SHIFT | CONTROL | AKEY_x;
706 			break;
707 		case XK_Y:
708 		case XK_y:
709 			keycode = SHIFT | CONTROL | AKEY_y;
710 			break;
711 		case XK_Z:
712 		case XK_z:
713 			keycode = SHIFT | CONTROL | AKEY_z;
714 			break;
715 		default:
716 			if (x11bug)
717 				printf("Pressed Keysym = %x\n", (int) keysym);
718 			break;
719 		}
720 		break;
721 	case KeyRelease:
722 		keycode = AKEY_NONE;
723 		switch (keysym) {
724 		case XK_Shift_L:
725 		case XK_Shift_R:
726 			INPUT_key_shift = 0;
727 			SHIFT = 0x00;
728 			break;
729 		case XK_Control_L:
730 			keypad_trig = 1;
731 			/* FALLTHROUGH */
732 		case XK_Control_R:
733 			CONTROL = 0x00;
734 			break;
735 		case XK_Shift_Lock:
736 			if (x11bug)
737 				printf("XK_Shift_Lock\n");
738 			break;
739 		case XK_F2:
740 			keyboard_consol |= INPUT_CONSOL_OPTION;
741 			break;
742 		case XK_F3:
743 			keyboard_consol |= INPUT_CONSOL_SELECT;
744 			break;
745 		case XK_F4:
746 			keyboard_consol |= INPUT_CONSOL_START;
747 			break;
748 		case XK_space:
749 		case XK_KP_0:
750 			keypad_trig = 1;
751 			break;
752 		case XK_Down:
753 		case XK_KP_2:
754 			keypad_stick |= INPUT_STICK_CENTRE ^ INPUT_STICK_BACK;
755 			break;
756 		case XK_Left:
757 		case XK_KP_4:
758 			keypad_stick |= INPUT_STICK_CENTRE ^ INPUT_STICK_LEFT;
759 			break;
760 		case XK_Right:
761 		case XK_KP_6:
762 			keypad_stick |= INPUT_STICK_CENTRE ^ INPUT_STICK_RIGHT;
763 			break;
764 		case XK_Up:
765 		case XK_KP_8:
766 			keypad_stick |= INPUT_STICK_CENTRE ^ INPUT_STICK_FORWARD;
767 			break;
768 		case XK_KP_1:
769 		case XK_KP_3:
770 		case XK_KP_5:
771 		case XK_KP_7:
772 		case XK_KP_9:
773 			keypad_stick = INPUT_STICK_CENTRE;
774 			break;
775 		default:
776 			break;
777 		}
778 		break;
779 	}
780 	return keycode;
781 }
782 
783 #if defined(XVIEW) || defined(MOTIF)
784 
insert_rom(const char * filename)785 static int insert_rom(const char *filename)
786 {
787 	int r;
788 	int i;
789 	r = CARTRIDGE_Insert(filename);
790 	if (r < 0)
791 		return FALSE;
792 	if (r == 0) {
793 		Atari800_Coldstart();
794 		return TRUE;
795 	}
796 	/* TODO: select cartridge type */
797 	for (i = 1; i < CARTRIDGE_LAST_SUPPORTED; i++) {
798 		if (CARTRIDGE_kb[i] == r) {
799 			CARTRIDGE_type = i;
800 			Atari800_Coldstart();
801 			return TRUE;
802 		}
803 	}
804 	return FALSE;
805 }
806 
807 static int xview_keycode = AKEY_NONE;
808 
809 #endif /* defined(XVIEW) || defined(MOTIF) */
810 
811 #ifdef XVIEW
812 
event_proc(Xv_Window window,Event * event,Notify_arg arg)813 static void event_proc(Xv_Window window, Event * event, Notify_arg arg)
814 {
815 	xview_keycode = GetKeyCode(event->ie_xevent);
816 }
817 
818 static int auto_reboot;
819 
disk_change(char * a,char * full_filename,char * filename)820 static int disk_change(char *a, char *full_filename, char *filename)
821 {
822 	int diskno;
823 	int status;
824 
825 	diskno = 1;
826 
827 	if (!auto_reboot)
828 		diskno = notice_prompt(panel, NULL,
829 							   NOTICE_MESSAGE_STRINGS,
830 							   "Insert Disk into which drive?",
831 							   NULL,
832 							   NOTICE_BUTTON, "1", 1,
833 							   NOTICE_BUTTON, "2", 2,
834 							   NOTICE_BUTTON, "3", 3,
835 							   NOTICE_BUTTON, "4", 4,
836 							   NOTICE_BUTTON, "5", 5,
837 							   NOTICE_BUTTON, "6", 6,
838 							   NOTICE_BUTTON, "7", 7,
839 							   NOTICE_BUTTON, "8", 8,
840 							   NULL);
841 
842 	if ((diskno < 1) || (diskno > 8)) {
843 		printf("Invalid diskno: %d\n", diskno);
844 		exit(1);
845 	}
846 	SIO_Dismount(diskno);
847 	if (!SIO_Mount(diskno, full_filename, FALSE))
848 		status = XV_ERROR;
849 	else {
850 		if (auto_reboot)
851 			Atari800_Coldstart();
852 		status = XV_OK;
853 	}
854 
855 	return status;
856 }
857 
boot_callback(void)858 static void boot_callback(void)
859 {
860 	static char dir[FILENAME_MAX];
861 	if (UI_n_atari_files_dir > 0)
862 		strcpy(dir, UI_atari_files_dir[0]);
863 	else
864 		dir[0] = '\0';
865 	auto_reboot = TRUE;
866 	xv_set(chooser,
867 		   FRAME_LABEL, "Disk Selector",
868 		   FILE_CHOOSER_DIRECTORY, dir,
869 		   FILE_CHOOSER_NOTIFY_FUNC, disk_change,
870 		   XV_SHOW, TRUE,
871 		   NULL);
872 }
873 
insert_callback(void)874 static void insert_callback(void)
875 {
876 	static char dir[FILENAME_MAX];
877 	if (UI_n_atari_files_dir > 0)
878 		strcpy(dir, UI_atari_files_dir[0]);
879 	else
880 		dir[0] = '\0';
881 	auto_reboot = FALSE;
882 	xv_set(chooser,
883 		   FRAME_LABEL, "Disk Selector",
884 		   FILE_CHOOSER_DIRECTORY, dir,
885 		   FILE_CHOOSER_NOTIFY_FUNC, disk_change,
886 		   XV_SHOW, TRUE,
887 		   NULL);
888 }
889 
eject_callback(void)890 static void eject_callback(void)
891 {
892 	int diskno;
893 
894 	diskno = notice_prompt(panel, NULL,
895 						   NOTICE_MESSAGE_STRINGS,
896 						   "Eject Disk from drive?",
897 						   NULL,
898 						   NOTICE_BUTTON, "1", 1,
899 						   NOTICE_BUTTON, "2", 2,
900 						   NOTICE_BUTTON, "3", 3,
901 						   NOTICE_BUTTON, "4", 4,
902 						   NOTICE_BUTTON, "5", 5,
903 						   NOTICE_BUTTON, "6", 6,
904 						   NOTICE_BUTTON, "7", 7,
905 						   NOTICE_BUTTON, "8", 8,
906 						   NULL);
907 
908 	if (diskno >= 1 && diskno <= 8)
909 		SIO_Dismount(diskno);
910 }
911 
disable_callback(void)912 static void disable_callback(void)
913 {
914 	int diskno;
915 
916 	diskno = notice_prompt(panel, NULL,
917 						   NOTICE_MESSAGE_STRINGS,
918 						   "Drive to Disable?",
919 						   NULL,
920 						   NOTICE_BUTTON, "1", 1,
921 						   NOTICE_BUTTON, "2", 2,
922 						   NOTICE_BUTTON, "3", 3,
923 						   NOTICE_BUTTON, "4", 4,
924 						   NOTICE_BUTTON, "5", 5,
925 						   NOTICE_BUTTON, "6", 6,
926 						   NOTICE_BUTTON, "7", 7,
927 						   NOTICE_BUTTON, "8", 8,
928 						   NULL);
929 
930 	if (diskno >= 1 && diskno <= 8)
931 		SIO_DisableDrive(diskno);
932 }
933 
rom_change(char * a,char * full_filename,char * filename)934 static int rom_change(char *a, char *full_filename, char *filename)
935 {
936 	return insert_rom(full_filename) ? XV_OK : XV_ERROR;
937 }
938 
insert_rom_callback(void)939 static void insert_rom_callback(void)
940 {
941 	static char dir[FILENAME_MAX];
942 	if (UI_n_atari_files_dir > 0)
943 		strcpy(dir, UI_atari_files_dir[0]);
944 	else
945 		dir[0] = '\0';
946 	xv_set(chooser,
947 		   FRAME_LABEL, "ROM Selector",
948 		   FILE_CHOOSER_DIRECTORY, dir,
949 		   FILE_CHOOSER_NOTIFY_FUNC, rom_change,
950 		   XV_SHOW, TRUE,
951 		   NULL);
952 }
953 
remove_rom_callback(void)954 static void remove_rom_callback(void)
955 {
956 	CARTRIDGE_Remove();
957 	Atari800_Coldstart();
958 }
959 
exit_callback(void)960 static void exit_callback(void)
961 {
962 	Atari800_Exit(FALSE);
963 	exit(1);
964 }
965 
option_callback(void)966 static void option_callback(void)
967 {
968 	menu_consol &= (~INPUT_CONSOL_OPTION);
969 }
970 
select_callback(void)971 static void select_callback(void)
972 {
973 	menu_consol &= (~INPUT_CONSOL_SELECT);
974 }
975 
start_callback(void)976 static void start_callback(void)
977 {
978 	menu_consol &= (~INPUT_CONSOL_START);
979 }
980 
reset_callback(void)981 static void reset_callback(void)
982 {
983 	Atari800_Warmstart();
984 }
985 
coldstart_callback(void)986 static void coldstart_callback(void)
987 {
988 	Atari800_Coldstart();
989 }
990 
coldstart_sys(int machtype,int ram,const char * errmsg)991 static void coldstart_sys(int machtype, int ram, const char *errmsg)
992 {
993 	Atari800_machine_type = machtype;
994 	MEMORY_ram_size = ram;
995 	if (!Atari800_InitialiseMachine()) {
996 		notice_prompt(panel, NULL,
997 					  NOTICE_MESSAGE_STRINGS,
998 					  errmsg,
999 					  NULL,
1000 					  NOTICE_BUTTON, "Cancel", 1,
1001 					  NULL);
1002 	}
1003 }
1004 
coldstart_osa_callback(void)1005 static void coldstart_osa_callback(void)
1006 {
1007 	coldstart_sys(Atari800_MACHINE_OSA, 48, "Sorry, OS/A ROM Unavailable");
1008 }
1009 
coldstart_osb_callback(void)1010 static void coldstart_osb_callback(void)
1011 {
1012 	coldstart_sys(Atari800_MACHINE_OSB, 48, "Sorry, OS/B ROM Unavailable");
1013 }
1014 
coldstart_xl_callback(void)1015 static void coldstart_xl_callback(void)
1016 {
1017 	coldstart_sys(Atari800_MACHINE_XLXE, 64, "Sorry, XL/XE ROM Unavailable");
1018 }
1019 
coldstart_xe_callback(void)1020 static void coldstart_xe_callback(void)
1021 {
1022 	coldstart_sys(Atari800_MACHINE_XLXE, 128, "Sorry, XL/XE ROM Unavailable");
1023 }
1024 
coldstart_5200_callback(void)1025 static void coldstart_5200_callback(void)
1026 {
1027 	coldstart_sys(Atari800_MACHINE_5200, 16, "Sorry, 5200 ROM Unavailable");
1028 }
1029 
controllers_ok_callback(void)1030 static void controllers_ok_callback(void)
1031 {
1032 	xv_set(controllers_frame,
1033 		   XV_SHOW, FALSE,
1034 		   NULL);
1035 }
1036 
controllers_callback(void)1037 static void controllers_callback(void)
1038 {
1039 	xv_set(controllers_frame,
1040 		   XV_SHOW, TRUE,
1041 		   NULL);
1042 }
1043 
sorry_message(void)1044 static void sorry_message(void)
1045 {
1046 	notice_prompt(panel, NULL,
1047 				  NOTICE_MESSAGE_STRINGS,
1048 				  "Sorry, controller already assigned",
1049 				  "to another device",
1050 				  NULL,
1051 				  NOTICE_BUTTON, "Cancel", 1,
1052 				  NULL);
1053 }
1054 
keypad_callback(void)1055 static void keypad_callback(void)
1056 {
1057 	int new_mode;
1058 
1059 	new_mode = xv_get(keypad_item, PANEL_VALUE);
1060 
1061 	if ((new_mode != xmouse_mode) &&
1062 		(new_mode != js0_mode) &&
1063 		(new_mode != js1_mode)) {
1064 		keypad_mode = new_mode;
1065 	}
1066 	else {
1067 		sorry_message();
1068 		xv_set(keypad_item,
1069 			   PANEL_VALUE, keypad_mode,
1070 			   NULL);
1071 	}
1072 }
1073 
mouse_callback(void)1074 static void mouse_callback(void)
1075 {
1076 	int new_mode;
1077 
1078 	new_mode = xv_get(mouse_item, PANEL_VALUE);
1079 
1080 	if ((new_mode != keypad_mode) &&
1081 		(new_mode != js0_mode) &&
1082 		(new_mode != js1_mode)) {
1083 		xmouse_mode = new_mode;
1084 	}
1085 	else {
1086 		sorry_message();
1087 		xv_set(mouse_item,
1088 			   PANEL_VALUE, xmouse_mode,
1089 			   NULL);
1090 	}
1091 }
1092 
1093 #ifdef LINUX_JOYSTICK
js0_callback(void)1094 static void js0_callback(void)
1095 {
1096 	int new_mode;
1097 
1098 	new_mode = xv_get(js0_item, PANEL_VALUE);
1099 
1100 	if ((new_mode != keypad_mode) &&
1101 		(new_mode != xmouse_mode) &&
1102 		(new_mode != js1_mode)) {
1103 		js0_mode = new_mode;
1104 	}
1105 	else {
1106 		sorry_message();
1107 		xv_set(js0_item,
1108 			   PANEL_VALUE, js0_mode,
1109 			   NULL);
1110 	}
1111 }
1112 
js1_callback(void)1113 static void js1_callback(void)
1114 {
1115 	int new_mode;
1116 
1117 	new_mode = xv_get(js1_item, PANEL_VALUE);
1118 
1119 	if ((new_mode != keypad_mode) &&
1120 		(new_mode != xmouse_mode) &&
1121 		(new_mode != js0_mode)) {
1122 		js1_mode = new_mode;
1123 	}
1124 	else {
1125 		sorry_message();
1126 		xv_set(js1_item,
1127 			   PANEL_VALUE, js1_mode,
1128 			   NULL);
1129 	}
1130 }
1131 #endif /* LINUX_JOYSTICK */
1132 
performance_ok_callback(void)1133 static void performance_ok_callback(void)
1134 {
1135 	xv_set(performance_frame,
1136 		   XV_SHOW, FALSE,
1137 		   NULL);
1138 }
1139 
performance_callback(void)1140 static void performance_callback(void)
1141 {
1142 	xv_set(performance_frame,
1143 		   XV_SHOW, TRUE,
1144 		   NULL);
1145 }
1146 
refresh_callback(Panel_item item,int value,Event * event)1147 static void refresh_callback(Panel_item item, int value, Event * event)
1148 {
1149 	Atari800_refresh_rate = value;
1150 }
1151 
1152 #endif /* XVIEW */
1153 
Atari_WhatIs(int mode)1154 static void Atari_WhatIs(int mode)
1155 {
1156 	switch (mode) {
1157 	case 0:
1158 		printf("Joystick 0");
1159 		break;
1160 	case 1:
1161 		printf("Joystick 1");
1162 		break;
1163 	case 2:
1164 		printf("Joystick 2");
1165 		break;
1166 	case 3:
1167 		printf("Joystick 3");
1168 		break;
1169 	default:
1170 		printf("not available");
1171 		break;
1172 	}
1173 }
1174 
1175 #ifdef MOTIF
1176 
motif_boot_disk(Widget fs,XtPointer client_data,XtPointer cbs)1177 static void motif_boot_disk(Widget fs, XtPointer client_data,
1178 					 XtPointer cbs)
1179 {
1180 	char *filename;
1181 
1182 	if (XmStringGetLtoR(((XmFileSelectionBoxCallbackStruct *) cbs)->value,
1183 						XmSTRING_DEFAULT_CHARSET, &filename)) {
1184 		if (*filename) {
1185 			SIO_Dismount(1);
1186 			if (SIO_Mount(1, filename, FALSE))
1187 				Atari800_Coldstart();
1188 		}
1189 		XtFree(filename);
1190 	}
1191 	XtUnmanageChild(fs);
1192 	XtPopdown(XtParent(fs));
1193 }
1194 
motif_select_disk(Widget toggle,XtPointer client_data,XtPointer cbs)1195 static void motif_select_disk(Widget toggle, XtPointer client_data, XtPointer cbs)
1196 {
1197 	motif_disk_sel = (int) client_data;
1198 }
1199 
motif_insert_disk(Widget fs,XtPointer client_data,XtPointer cbs)1200 static void motif_insert_disk(Widget fs, XtPointer client_data, XtPointer cbs)
1201 {
1202 	char *filename;
1203 
1204 	if (XmStringGetLtoR(((XmFileSelectionBoxCallbackStruct *) cbs)->value,
1205 						XmSTRING_DEFAULT_CHARSET, &filename)) {
1206 		if (*filename) {
1207 			SIO_Dismount(motif_disk_sel);
1208 			SIO_Mount(motif_disk_sel, filename, FALSE);
1209 		}
1210 		XtFree(filename);
1211 	}
1212 	XtUnmanageChild(fs);
1213 	XtPopdown(XtParent(fs));
1214 }
1215 
motif_insert_rom(Widget fs,XtPointer client_data,XtPointer cbs)1216 static void motif_insert_rom(Widget fs, XtPointer client_data, XtPointer cbs)
1217 {
1218 	char *filename;
1219 
1220 	if (XmStringGetLtoR(((XmFileSelectionBoxCallbackStruct *) cbs)->value,
1221 						XmSTRING_DEFAULT_CHARSET, &filename)) {
1222 		if (*filename) {
1223 			insert_rom(filename);
1224 		}
1225 		XtFree(filename);
1226 	}
1227 	XtUnmanageChild(fs);
1228 	XtPopdown(XtParent(fs));
1229 }
1230 
motif_fs_cancel(Widget fs,XtPointer client_data,XtPointer call_data)1231 static void motif_fs_cancel(Widget fs, XtPointer client_data, XtPointer call_data)
1232 {
1233 	XtUnmanageChild(fs);
1234 	XtPopdown(XtParent(fs));
1235 }
1236 
motif_eject_cback(Widget button,XtPointer client_data,XtPointer cbs)1237 static void motif_eject_cback(Widget button, XtPointer client_data, XtPointer cbs)
1238 {
1239 	SIO_Dismount(((int) client_data) + 1);
1240 }
1241 
motif_disable_cback(Widget button,XtPointer client_data,XtPointer cbs)1242 static void motif_disable_cback(Widget button, XtPointer client_data, XtPointer cbs)
1243 {
1244 	SIO_DisableDrive(((int) client_data) + 1);
1245 }
1246 
update_fsel(Widget fsel)1247 static void update_fsel(Widget fsel)
1248 {
1249 	XmString dirmask;
1250 
1251 	XtVaGetValues(fsel, XmNdirMask, &dirmask, NULL);
1252 	XmFileSelectionDoSearch(fsel, dirmask);
1253 }
1254 
motif_system_cback(Widget w,XtPointer item_no,XtPointer cbs)1255 static void motif_system_cback(Widget w, XtPointer item_no, XtPointer cbs)
1256 {
1257 	XmString t;
1258 	int status;
1259 	char *errmsg = NULL;
1260 
1261 	switch ((int) item_no) {
1262 	case 0:
1263 		update_fsel(fsel_b);
1264 		XtManageChild(fsel_b);
1265 		XtPopup(XtParent(fsel_b), XtGrabNone);
1266 		break;
1267 	case 1:
1268 		/* insert disk */
1269 		update_fsel(fsel_d);
1270 		XtManageChild(fsel_d);
1271 		XtPopup(XtParent(fsel_d), XtGrabNone);
1272 		break;
1273 	case 2:
1274 		/* eject disk */
1275 		/* handled by pullright menu */
1276 		break;
1277 	case 3:
1278 		/* disable drive */
1279 		/* handled by pullright menu */
1280 		break;
1281 	case 4:
1282 		/* insert rom */
1283 		update_fsel(fsel_r);
1284 		XtManageChild(fsel_r);
1285 		XtPopup(XtParent(fsel_r), XtGrabNone);
1286 		break;
1287 	case 5:
1288 		CARTRIDGE_Remove();
1289 		Atari800_Coldstart();
1290 		break;
1291 	case 6:
1292 		Atari800_machine_type = Atari800_MACHINE_OSA;
1293 		MEMORY_ram_size = 48;
1294 		status = Atari800_InitialiseMachine();
1295 		if (status == 0)
1296 			errmsg = "Sorry, OS/A ROM Unavailable";
1297 		break;
1298 	case 7:
1299 		Atari800_machine_type = Atari800_MACHINE_OSB;
1300 		MEMORY_ram_size = 48;
1301 		status = Atari800_InitialiseMachine();
1302 		if (status == 0)
1303 			errmsg = "Sorry, OS/B ROM Unavailable";
1304 		break;
1305 	case 8:
1306 		Atari800_machine_type = Atari800_MACHINE_XLXE;
1307 		MEMORY_ram_size = 64;
1308 		status = Atari800_InitialiseMachine();
1309 		if (status == 0)
1310 			errmsg = "Sorry, XL/XE ROM Unavailable";
1311 		break;
1312 	case 9:
1313 		Atari800_machine_type = Atari800_MACHINE_XLXE;
1314 		MEMORY_ram_size = 128;
1315 		status = Atari800_InitialiseMachine();
1316 		if (status == 0)
1317 			errmsg = "Sorry, XL/XE ROM Unavailable";
1318 		break;
1319 	case 10:
1320 		Atari800_machine_type = Atari800_MACHINE_5200;
1321 		MEMORY_ram_size = 16;
1322 		status = Atari800_InitialiseMachine();
1323 		if (status == 0)
1324 			errmsg = "Sorry, 5200 ROM Unavailable";
1325 		break;
1326 	case 11:
1327 		Atari800_Exit(FALSE);
1328 		exit(0);
1329 	}
1330 
1331 	if (errmsg) {
1332 		static Widget dialog = NULL;
1333 
1334 		if (!dialog) {
1335 			Arg arg[1];
1336 
1337 			dialog = XmCreateErrorDialog(main_w, "message", arg, 0);
1338 
1339 			XtVaSetValues(dialog,
1340 						  XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL,
1341 						  NULL);
1342 
1343 			XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_OK_BUTTON));
1344 			XtUnmanageChild(XmMessageBoxGetChild(dialog, XmDIALOG_HELP_BUTTON));
1345 		}
1346 		t = XmStringCreateSimple(errmsg);
1347 		XtVaSetValues(dialog,
1348 					  XmNmessageString, t,
1349 					  NULL);
1350 		XmStringFree(t);
1351 		XtManageChild(dialog);
1352 	}
1353 }
1354 
motif_consol_cback(Widget w,XtPointer item_no,XtPointer cbs)1355 static void motif_consol_cback(Widget w, XtPointer item_no, XtPointer cbs)
1356 {
1357 	switch ((int) item_no) {
1358 	case 0:
1359 		menu_consol &= (~INPUT_CONSOL_OPTION);
1360 		break;
1361 	case 1:
1362 		menu_consol &= (~INPUT_CONSOL_SELECT);
1363 		break;
1364 	case 2:
1365 		menu_consol &= (~INPUT_CONSOL_START);
1366 		break;
1367 	case 3:
1368 		Atari800_Warmstart();
1369 		break;
1370 	case 4:
1371 		Atari800_Coldstart();
1372 		break;
1373 	}
1374 }
1375 
motif_keypress(Widget w,XtPointer client_data,XEvent * event,Boolean * continue_to_dispatch)1376 static void motif_keypress(Widget w, XtPointer client_data, XEvent *event,
1377                            Boolean *continue_to_dispatch)
1378 {
1379 	xview_keycode = GetKeyCode(event);
1380 }
1381 
motif_exposure(Widget w,XtPointer client_data,XEvent * event,Boolean * continue_to_dispatch)1382 static void motif_exposure(Widget w, XtPointer client_data, XEvent *event,
1383 					Boolean *continue_to_dispatch)
1384 {
1385 	modified = TRUE;
1386 }
1387 
1388 #endif /* MOTIF */
1389 
PLATFORM_Initialise(int * argc,char * argv[])1390 int PLATFORM_Initialise(int *argc, char *argv[])
1391 {
1392 #if !defined(XVIEW) && !defined(MOTIF)
1393 	XSetWindowAttributes xswda;
1394 #endif
1395 
1396 	XGCValues xgcvl;
1397 
1398 	int depth;
1399 	int colorstep;
1400 	int i, j;
1401 	int mode = 0;
1402 	int help_only = FALSE;
1403 
1404 #ifdef XVIEW
1405 	int ypos;
1406 
1407 	xv_init(XV_INIT_ARGC_PTR_ARGV, argc, argv, NULL);
1408 #endif
1409 
1410 #ifdef MOTIF
1411 	toplevel = XtVaAppInitialize(&app, "Atari800",
1412 								 NULL, 0,
1413 								 argc, argv, NULL,
1414 								 XtNtitle, Atari800_TITLE,
1415 								 NULL);
1416 #endif
1417 
1418 	for (i = j = 1; i < *argc; i++) {
1419 		int i_a = (i + 1 < *argc);		/* is argument available? */
1420 		int a_m = FALSE;			/* error, argument missing! */
1421 
1422 		if (strcmp(argv[i], "-small") == 0)
1423 			windowsize = Small;
1424 		else if (strcmp(argv[i], "-large") == 0)
1425 			windowsize = Large;
1426 		else if (strcmp(argv[i], "-huge") == 0)
1427 			windowsize = Huge;
1428 		else if (strcmp(argv[i], "-clip_x") == 0)
1429 			if (i_a)
1430 				clipping_x = atoi(argv[++i]);
1431 			else a_m = TRUE;
1432 		else if (strcmp(argv[i], "-clip_y") == 0)
1433 			if (i_a)
1434 				clipping_y = atoi(argv[++i]);
1435 			else a_m = TRUE;
1436 		else if (strcmp(argv[i], "-clip_width") == 0)
1437 			if (i_a)
1438 				clipping_width = atoi(argv[++i]);
1439 			else a_m = TRUE;
1440 		else if (strcmp(argv[i], "-clip_height") == 0)
1441 			if (i_a)
1442 				clipping_height = atoi(argv[++i]);
1443 			else a_m = TRUE;
1444 		else if (strcmp(argv[i], "-x11bug") == 0)
1445 			x11bug = TRUE;
1446 		else if (strcmp(argv[i], "-sio") == 0)
1447 			x11_monitor = MONITOR_SIO;
1448 		else if (strcmp(argv[i], "-private_cmap") == 0)
1449 			private_cmap = TRUE;
1450 		else if (strcmp(argv[i], "-keypad") == 0) {
1451 			if (keypad_mode == -1)
1452 				keypad_mode = mode++;
1453 		}
1454 		else {
1455 			if (strcmp(argv[i], "-help") == 0) {
1456 				help_only = TRUE;
1457 				printf("\t-small           Small window (%dx%d)\n",
1458 					   clipping_width, clipping_height);
1459 				printf("\t-large           Large window (%dx%d)\n",
1460 					   clipping_width * 2, clipping_height * 2);
1461 				printf("\t-huge            Huge window (%dx%d)\n",
1462 					   clipping_width * 3, clipping_height * 3);
1463 				printf("\t-x11bug          Enable debug code in atari_x11.c\n");
1464 				printf("\t-clip_x <n>      Set left offset in pixels for clipping\n");
1465 				printf("\t-clip_width <n>  Set window clip-width\n");
1466 				printf("\t-clip_y <n>      Set top offset for clipping\n");
1467 				printf("\t-clip_height <n> Set window clip-height\n");
1468 				printf("\t-private_cmap    Use private colormap\n");
1469 				printf("\t-sio             Show SIO monitor\n");
1470 				printf("\t-keypad          Keypad mode\n");
1471 			}
1472 			argv[j++] = argv[i];
1473 		}
1474 	}
1475 
1476 	*argc = j;
1477 
1478 #ifdef SOUND
1479 	if (!Sound_Initialise(argc, argv))
1480 		return FALSE;
1481 #endif
1482 
1483 	if (help_only)
1484 		return TRUE;
1485 
1486 	if ((clipping_x < 0) || (clipping_x >= Screen_WIDTH))
1487 		clipping_x = 0;
1488 	if ((clipping_y < 0) || (clipping_y >= Screen_HEIGHT))
1489 		clipping_y = 0;
1490 	if ((clipping_width <= 0) || (clipping_x + clipping_width > Screen_WIDTH))
1491 		clipping_width = Screen_WIDTH - clipping_x;
1492 	if ((clipping_height <= 0) || (clipping_y + clipping_height > Screen_HEIGHT))
1493 		clipping_height = Screen_HEIGHT - clipping_y;
1494 	Screen_visible_x1 = clipping_x;
1495 	Screen_visible_x2 = clipping_x + clipping_width;
1496 	Screen_visible_y1 = clipping_y;
1497 	Screen_visible_y2 = clipping_y + clipping_height;
1498 	switch (windowsize) {
1499 	case Small:
1500 		clipping_factor = 1;
1501 		window_width = clipping_width;
1502 		window_height = clipping_height;
1503 		break;
1504 	case Large:
1505 		clipping_factor = 2;
1506 		window_width = clipping_width * 2;
1507 		window_height = clipping_height * 2;
1508 		break;
1509 	case Huge:
1510 		clipping_factor = 3;
1511 		window_width = clipping_width * 3;
1512 		window_height = clipping_height * 3;
1513 		break;
1514 	}
1515 
1516 #ifdef LINUX_JOYSTICK
1517 	js0 = open("/dev/js0", O_RDONLY, 0777);
1518 	if (js0 != -1) {
1519 		int status;
1520 
1521 		status = read(js0, &js_data, JS_RETURN);
1522 		if (status != JS_RETURN) {
1523 			perror("/dev/js0");
1524 			exit(1);
1525 		}
1526 		js0_centre_x = js_data.x;
1527 		js0_centre_y = js_data.y;
1528 
1529 		if (x11bug)
1530 			printf("Joystick 0: centre_x = %d, centry_y = %d\n",
1531 				   js0_centre_x, js0_centre_y);
1532 
1533 		js0_mode = mode++;
1534 	}
1535 	js1 = open("/dev/js1", O_RDONLY, 0777);
1536 	if (js1 != -1) {
1537 		int status;
1538 
1539 		status = read(js1, &js_data, JS_RETURN);
1540 		if (status != JS_RETURN) {
1541 			perror("/dev/js1");
1542 			exit(1);
1543 		}
1544 		js1_centre_x = js_data.x;
1545 		js1_centre_y = js_data.y;
1546 
1547 		if (x11bug)
1548 			printf("Joystick 1: centre_x = %d, centry_y = %d\n",
1549 				   js1_centre_x, js1_centre_y);
1550 
1551 		js1_mode = mode++;
1552 	}
1553 #endif
1554 
1555 	xmouse_mode = mode++;
1556 	if (keypad_mode == -1)
1557 		keypad_mode = mode++;
1558 
1559 #ifdef XVIEW
1560 	frame = (Frame) xv_create((Xv_opaque) NULL, FRAME,
1561 							  FRAME_LABEL, Atari800_TITLE,
1562 							  FRAME_SHOW_RESIZE_CORNER, FALSE,
1563 							  XV_WIDTH, window_width,
1564 							  XV_HEIGHT, window_height + 27,
1565 							  FRAME_SHOW_FOOTER, TRUE,
1566 							  XV_SHOW, TRUE,
1567 							  NULL);
1568 
1569 	panel = (Panel) xv_create(frame, PANEL,
1570 							  XV_HEIGHT, 25,
1571 							  XV_SHOW, TRUE,
1572 							  NULL);
1573 
1574 	system_menu = xv_create((Xv_opaque) NULL, MENU,
1575 							MENU_ITEM,
1576 							MENU_STRING, "Boot Disk",
1577 							MENU_NOTIFY_PROC, boot_callback,
1578 							NULL,
1579 							MENU_ITEM,
1580 							MENU_STRING, "Insert Disk",
1581 							MENU_NOTIFY_PROC, insert_callback,
1582 							NULL,
1583 							MENU_ITEM,
1584 							MENU_STRING, "Eject Disk",
1585 							MENU_NOTIFY_PROC, eject_callback,
1586 							NULL,
1587 							MENU_ITEM,
1588 							MENU_STRING, "Disable Drive",
1589 							MENU_NOTIFY_PROC, disable_callback,
1590 							NULL,
1591 							MENU_ITEM,
1592 							MENU_STRING, "Insert Cartridge",
1593 							MENU_NOTIFY_PROC, insert_rom_callback,
1594 							NULL,
1595 							MENU_ITEM,
1596 							MENU_STRING, "Remove Cartridge",
1597 							MENU_NOTIFY_PROC, remove_rom_callback,
1598 							NULL,
1599 							MENU_ITEM,
1600 							MENU_STRING, "Atari 800 OS/A",
1601 							MENU_NOTIFY_PROC, coldstart_osa_callback,
1602 							NULL,
1603 							MENU_ITEM,
1604 							MENU_STRING, "Atari 800 OS/B",
1605 							MENU_NOTIFY_PROC, coldstart_osb_callback,
1606 							NULL,
1607 							MENU_ITEM,
1608 							MENU_STRING, "Atari 800XL",
1609 							MENU_NOTIFY_PROC, coldstart_xl_callback,
1610 							NULL,
1611 							MENU_ITEM,
1612 							MENU_STRING, "Atari 130XE",
1613 							MENU_NOTIFY_PROC, coldstart_xe_callback,
1614 							NULL,
1615 							MENU_ITEM,
1616 							MENU_STRING, "Atari 5200",
1617 							MENU_NOTIFY_PROC, coldstart_5200_callback,
1618 							NULL,
1619 							MENU_ITEM,
1620 							MENU_STRING, "Exit",
1621 							MENU_NOTIFY_PROC, exit_callback,
1622 							NULL,
1623 							NULL);
1624 
1625 	xv_create(panel, PANEL_BUTTON,
1626 			  PANEL_LABEL_STRING, "System",
1627 			  PANEL_ITEM_MENU, system_menu,
1628 			  NULL);
1629 
1630 	consol_menu = (Menu) xv_create((Xv_opaque) NULL, MENU,
1631 								   MENU_ITEM,
1632 								   MENU_STRING, "Option",
1633 								   MENU_NOTIFY_PROC, option_callback,
1634 								   NULL,
1635 								   MENU_ITEM,
1636 								   MENU_STRING, "Select",
1637 								   MENU_NOTIFY_PROC, select_callback,
1638 								   NULL,
1639 								   MENU_ITEM,
1640 								   MENU_STRING, "Start",
1641 								   MENU_NOTIFY_PROC, start_callback,
1642 								   NULL,
1643 								   MENU_ITEM,
1644 								   MENU_STRING, "Reset",
1645 								   MENU_NOTIFY_PROC, reset_callback,
1646 								   NULL,
1647 								   MENU_ITEM,
1648 								   MENU_STRING, "Coldstart",
1649 								   MENU_NOTIFY_PROC, coldstart_callback,
1650 								   NULL,
1651 								   NULL);
1652 
1653 	xv_create(panel, PANEL_BUTTON,
1654 			  PANEL_LABEL_STRING, "Console",
1655 			  PANEL_ITEM_MENU, consol_menu,
1656 			  NULL);
1657 
1658 	options_menu = (Menu) xv_create((Xv_opaque) NULL, MENU,
1659 									MENU_ITEM,
1660 									MENU_STRING, "Controllers",
1661 								  MENU_NOTIFY_PROC, controllers_callback,
1662 									NULL,
1663 									MENU_ITEM,
1664 									MENU_STRING, "Performance",
1665 								  MENU_NOTIFY_PROC, performance_callback,
1666 									NULL,
1667 									NULL);
1668 
1669 	xv_create(panel, PANEL_BUTTON,
1670 			  PANEL_LABEL_STRING, "Options",
1671 			  PANEL_ITEM_MENU, options_menu,
1672 			  NULL);
1673 
1674 	canvas = (Canvas) xv_create(frame, CANVAS,
1675 								CANVAS_WIDTH, window_width,
1676 								CANVAS_HEIGHT, window_height,
1677 								NULL);
1678 /*
1679    =====================================
1680    Create Controller Configuration Frame
1681    =====================================
1682  */
1683 	controllers_frame = (Frame) xv_create(frame, FRAME_CMD,
1684 								 FRAME_LABEL, "Controller Configuration",
1685 										  XV_WIDTH, 300,
1686 										  XV_HEIGHT, 150,
1687 										  NULL);
1688 
1689 	controllers_panel = (Panel) xv_get(controllers_frame, FRAME_CMD_PANEL,
1690 									   NULL);
1691 
1692 	ypos = 10;
1693 	keypad_item = (Panel_item) xv_create(controllers_panel, PANEL_CHOICE_STACK,
1694 										 PANEL_VALUE_X, 150,
1695 										 PANEL_VALUE_Y, ypos,
1696 										 PANEL_LAYOUT, PANEL_HORIZONTAL,
1697 										 PANEL_LABEL_STRING, "Numeric Keypad",
1698 										 PANEL_CHOICE_STRINGS,
1699 										 "Joystick 1",
1700 										 "Joystick 2",
1701 										 "Joystick 3",
1702 										 "Joystick 4",
1703 										 NULL,
1704 										 PANEL_VALUE, keypad_mode,
1705 										 PANEL_NOTIFY_PROC, keypad_callback,
1706 										 NULL);
1707 	ypos += 25;
1708 
1709 	mouse_item = (Panel_item) xv_create(controllers_panel, PANEL_CHOICE_STACK,
1710 										PANEL_VALUE_X, 150,
1711 										PANEL_VALUE_Y, ypos,
1712 										PANEL_LAYOUT, PANEL_HORIZONTAL,
1713 										PANEL_LABEL_STRING, "Mouse",
1714 										PANEL_CHOICE_STRINGS,
1715 										"Joystick 1",
1716 										"Joystick 2",
1717 										"Joystick 3",
1718 										"Joystick 4",
1719 										NULL,
1720 										PANEL_VALUE, xmouse_mode,
1721 										PANEL_NOTIFY_PROC, mouse_callback,
1722 										NULL);
1723 	ypos += 25;
1724 
1725 #ifdef LINUX_JOYSTICK
1726 	if (js0 != -1) {
1727 		js0_item = (Panel_item) xv_create(controllers_panel, PANEL_CHOICE_STACK,
1728 										  PANEL_VALUE_X, 150,
1729 										  PANEL_VALUE_Y, ypos,
1730 										  PANEL_LAYOUT, PANEL_HORIZONTAL,
1731 										  PANEL_LABEL_STRING, "/dev/js0",
1732 										  PANEL_CHOICE_STRINGS,
1733 										  "Joystick 1",
1734 										  "Joystick 2",
1735 										  "Joystick 3",
1736 										  "Joystick 4",
1737 										  NULL,
1738 										  PANEL_VALUE, js0_mode,
1739 										  PANEL_NOTIFY_PROC, js0_callback,
1740 										  NULL);
1741 		ypos += 25;
1742 	}
1743 	if (js1 != -1) {
1744 		js1_item = (Panel_item) xv_create(controllers_panel, PANEL_CHOICE_STACK,
1745 										  PANEL_VALUE_X, 150,
1746 										  PANEL_VALUE_Y, ypos,
1747 										  PANEL_LAYOUT, PANEL_HORIZONTAL,
1748 										  PANEL_LABEL_STRING, "/dev/js1",
1749 										  PANEL_CHOICE_STRINGS,
1750 										  "Joystick 1",
1751 										  "Joystick 2",
1752 										  "Joystick 3",
1753 										  "Joystick 4",
1754 										  NULL,
1755 										  PANEL_VALUE, js1_mode,
1756 										  PANEL_NOTIFY_PROC, js1_callback,
1757 										  NULL);
1758 		ypos += 25;
1759 	}
1760 #endif
1761 
1762 	xv_create(controllers_panel, PANEL_BUTTON,
1763 			  XV_X, 130,
1764 			  XV_Y, 125,
1765 			  PANEL_LABEL_STRING, "OK",
1766 			  PANEL_NOTIFY_PROC, controllers_ok_callback,
1767 			  NULL);
1768 /*
1769    ======================================
1770    Create Performance Configuration Frame
1771    ======================================
1772  */
1773 	performance_frame = (Frame) xv_create(frame, FRAME_CMD,
1774 								FRAME_LABEL, "Performance Configuration",
1775 										  XV_WIDTH, 400,
1776 										  XV_HEIGHT, 100,
1777 										  NULL);
1778 
1779 	performance_panel = (Panel) xv_get(performance_frame, FRAME_CMD_PANEL,
1780 									   NULL);
1781 
1782 	ypos = 10;
1783 	refresh_slider = (Panel_item) xv_create(performance_panel, PANEL_SLIDER,
1784 											PANEL_VALUE_X, 155,
1785 											PANEL_VALUE_Y, ypos,
1786 											PANEL_LAYOUT, PANEL_HORIZONTAL,
1787 											PANEL_LABEL_STRING, "Screen Refresh Rate",
1788 											PANEL_VALUE, Atari800_refresh_rate,
1789 											PANEL_MIN_VALUE, 1,
1790 											PANEL_MAX_VALUE, 32,
1791 											PANEL_SLIDER_WIDTH, 100,
1792 											PANEL_TICKS, 32,
1793 											PANEL_NOTIFY_PROC, refresh_callback,
1794 											NULL);
1795 	ypos += 25;
1796 
1797 	xv_create(performance_panel, PANEL_BUTTON,
1798 			  XV_X, 180,
1799 			  XV_Y, 75,
1800 			  PANEL_LABEL_STRING, "OK",
1801 			  PANEL_NOTIFY_PROC, performance_ok_callback,
1802 			  NULL);
1803 /*
1804    ====================
1805    Get X Window Objects
1806    ====================
1807  */
1808 	display = (Display *) xv_get(frame, XV_DISPLAY);
1809 	if (!display) {
1810 		printf("Failed to open display\n");
1811 		exit(1);
1812 	}
1813 	autorepeat_get();
1814 	screen = XDefaultScreenOfDisplay(display);
1815 	if (!screen) {
1816 		printf("Unable to get screen\n");
1817 		exit(1);
1818 	}
1819 	visual = XDefaultVisualOfScreen(screen);
1820 	if (!visual) {
1821 		printf("Unable to get visual\n");
1822 		exit(1);
1823 	}
1824 	window = (Window) xv_get(canvas_paint_window(canvas), XV_XID);
1825 	depth = XDefaultDepthOfScreen(screen);
1826 	cmap = XDefaultColormapOfScreen(screen);
1827 
1828 	chooser = (Frame) xv_create(frame, FILE_CHOOSER,
1829 								FILE_CHOOSER_TYPE, FILE_CHOOSER_OPEN,
1830 								NULL);
1831 
1832 	xv_set(canvas_paint_window(canvas),
1833 		   WIN_EVENT_PROC, event_proc,
1834 		   WIN_CONSUME_EVENTS, WIN_ASCII_EVENTS, WIN_MOUSE_BUTTONS,
1835 		   WIN_VISIBILITY_NOTIFY, /* mmm */
1836 		   NULL,
1837 		   NULL);
1838 
1839 #endif /* XVIEW */
1840 
1841 #ifdef MOTIF
1842 	{
1843 		Widget menubar;
1844 
1845 		XmString s_system;
1846 		XmString s_boot_disk;
1847 		XmString s_insert_disk;
1848 		XmString s_eject_disk;
1849 		XmString s_disable_drive;
1850 		XmString s_insert_cart;
1851 		XmString s_remove_cart;
1852 		XmString s_osa;
1853 		XmString s_osb;
1854 		XmString s_osxl;
1855 		XmString s_osxe;
1856 		XmString s_os5200;
1857 		XmString s_exit;
1858 
1859 		XmString s_console;
1860 		XmString s_option;
1861 		XmString s_select;
1862 		XmString s_start;
1863 		XmString s_warmstart;
1864 		XmString s_coldstart;
1865 
1866 		XmString s_label;
1867 
1868 		XmString s_d1, s_d2, s_d3, s_d4;
1869 		XmString s_d5, s_d6, s_d7, s_d8;
1870 
1871 		char *tmpstr;
1872 		XmString xmtmpstr;
1873 
1874 		Arg args[8];
1875 		int n;
1876 
1877 		main_w = XtVaCreateManagedWidget("main_window",
1878 									   xmMainWindowWidgetClass, toplevel,
1879 										 NULL);
1880 
1881 		s_system = XmStringCreateSimple("System");
1882 		s_boot_disk = XmStringCreateSimple("Boot Disk...");
1883 		s_insert_disk = XmStringCreateSimple("Insert Disk...");
1884 		s_eject_disk = XmStringCreateSimple("Eject Disk");
1885 		s_disable_drive = XmStringCreateSimple("Disable Drive");
1886 		s_insert_cart = XmStringCreateSimple("Insert Cartridge...");
1887 		s_remove_cart = XmStringCreateSimple("Remove Cartridge");
1888 		s_osa = XmStringCreateSimple("Atari 800 OS/A");
1889 		s_osb = XmStringCreateSimple("Atari 800 OS/B");
1890 		s_osxl = XmStringCreateSimple("Atari 800XL");
1891 		s_osxe = XmStringCreateSimple("Atari 130XE");
1892 		s_os5200 = XmStringCreateSimple("Atari 5200");
1893 		s_exit = XmStringCreateSimple("Exit");
1894 
1895 		s_console = XmStringCreateSimple("Console");
1896 		s_option = XmStringCreateSimple("Option");
1897 		s_select = XmStringCreateSimple("Select");
1898 		s_start = XmStringCreateSimple("Start");
1899 		s_warmstart = XmStringCreateSimple("Warmstart");
1900 		s_coldstart = XmStringCreateSimple("Coldstart");
1901 
1902 		menubar = XmVaCreateSimpleMenuBar(main_w, "menubar",
1903 										XmVaCASCADEBUTTON, s_system, 'S',
1904 									   XmVaCASCADEBUTTON, s_console, 'C',
1905 										  NULL);
1906 
1907 		system_menu =
1908 			XmVaCreateSimplePulldownMenu(menubar, "system_menu", 0, motif_system_cback,
1909 							XmVaPUSHBUTTON, s_boot_disk, 'o', NULL, NULL,
1910 						  XmVaPUSHBUTTON, s_insert_disk, 'I', NULL, NULL,
1911 									XmVaCASCADEBUTTON, s_eject_disk, 'j',
1912 								 XmVaCASCADEBUTTON, s_disable_drive, 'D',
1913 										 XmVaSEPARATOR,
1914 						  XmVaPUSHBUTTON, s_insert_cart, 'n', NULL, NULL,
1915 						  XmVaPUSHBUTTON, s_remove_cart, 'R', NULL, NULL,
1916 										 XmVaSEPARATOR,
1917 								  XmVaPUSHBUTTON, s_osa, 'A', NULL, NULL,
1918 								  XmVaPUSHBUTTON, s_osb, 'B', NULL, NULL,
1919 								 XmVaPUSHBUTTON, s_osxl, 'L', NULL, NULL,
1920 								 XmVaPUSHBUTTON, s_osxe, 'E', NULL, NULL,
1921 							   XmVaPUSHBUTTON, s_os5200, '5', NULL, NULL,
1922 										 XmVaSEPARATOR,
1923 								 XmVaPUSHBUTTON, s_exit, 'x', NULL, NULL,
1924 										 NULL);
1925 
1926 		XmVaCreateSimplePulldownMenu(menubar, "console_menu", 1, motif_consol_cback,
1927 							   XmVaPUSHBUTTON, s_option, 'O', NULL, NULL,
1928 							   XmVaPUSHBUTTON, s_select, 't', NULL, NULL,
1929 								XmVaPUSHBUTTON, s_start, 'S', NULL, NULL,
1930 									 XmVaSEPARATOR,
1931 							XmVaPUSHBUTTON, s_warmstart, 'W', NULL, NULL,
1932 							XmVaPUSHBUTTON, s_coldstart, 'C', NULL, NULL,
1933 									 NULL);
1934 
1935 		XmStringFree(s_system);
1936 		XmStringFree(s_boot_disk);
1937 		XmStringFree(s_insert_disk);
1938 		XmStringFree(s_eject_disk);
1939 		XmStringFree(s_disable_drive);
1940 		XmStringFree(s_insert_cart);
1941 		XmStringFree(s_remove_cart);
1942 		XmStringFree(s_osa);
1943 		XmStringFree(s_osb);
1944 		XmStringFree(s_osxl);
1945 		XmStringFree(s_osxe);
1946 		XmStringFree(s_os5200);
1947 		XmStringFree(s_exit);
1948 
1949 		XmStringFree(s_console);
1950 		XmStringFree(s_option);
1951 		XmStringFree(s_select);
1952 		XmStringFree(s_start);
1953 		XmStringFree(s_warmstart);
1954 		XmStringFree(s_coldstart);
1955 
1956 		XtManageChild(menubar);
1957 
1958 		fsel_b = XmCreateFileSelectionDialog(toplevel, "boot_disk", NULL, 0);
1959 		XtAddCallback(fsel_b, XmNokCallback, motif_boot_disk, NULL);
1960 		XtAddCallback(fsel_b, XmNcancelCallback, motif_fs_cancel, NULL);
1961 
1962 		fsel_d = XmCreateFileSelectionDialog(toplevel, "load_disk", NULL, 0);
1963 		XtAddCallback(fsel_d, XmNokCallback, motif_insert_disk, NULL);
1964 		XtAddCallback(fsel_d, XmNcancelCallback, motif_fs_cancel, NULL);
1965 
1966 		n = 0;
1967 		XtSetArg(args[n], XmNradioBehavior, True);
1968 		n++;
1969 		XtSetArg(args[n], XmNradioAlwaysOne, True);
1970 		n++;
1971 		XtSetArg(args[n], XmNorientation, XmHORIZONTAL);
1972 		n++;
1973 		rbox_d = XmCreateWorkArea(fsel_d, "rbox_d", args, n);
1974 		XtManageChild(rbox_d);
1975 
1976 		s_label = XmStringCreateSimple("D1:");
1977 		n = 0;
1978 		XtSetArg(args[n], XmNlabelString, s_label);
1979 		n++;
1980 		XtSetArg(args[n], XmNset, True);
1981 		n++;
1982 		togg_d1 = XmCreateToggleButtonGadget(rbox_d, "togg_d1", args, n);
1983 		XtManageChild(togg_d1);
1984 		XmStringFree(s_label);
1985 		XtAddCallback(togg_d1, XmNarmCallback, motif_select_disk, (XtPointer) 1);
1986 
1987 		s_label = XmStringCreateSimple("D2:");
1988 		n = 0;
1989 		XtSetArg(args[n], XmNlabelString, s_label);
1990 		n++;
1991 		togg_d2 = XmCreateToggleButtonGadget(rbox_d, "togg_d2", args, n);
1992 		XtManageChild(togg_d2);
1993 		XmStringFree(s_label);
1994 		XtAddCallback(togg_d2, XmNarmCallback, motif_select_disk, (XtPointer) 2);
1995 
1996 		s_label = XmStringCreateSimple("D3:");
1997 		n = 0;
1998 		XtSetArg(args[n], XmNlabelString, s_label);
1999 		n++;
2000 		togg_d3 = XmCreateToggleButtonGadget(rbox_d, "togg_d3", args, n);
2001 		XtManageChild(togg_d3);
2002 		XmStringFree(s_label);
2003 		XtAddCallback(togg_d3, XmNarmCallback, motif_select_disk, (XtPointer) 3);
2004 
2005 		s_label = XmStringCreateSimple("D4:");
2006 		n = 0;
2007 		XtSetArg(args[n], XmNlabelString, s_label);
2008 		n++;
2009 		togg_d4 = XmCreateToggleButtonGadget(rbox_d, "togg_d4", args, n);
2010 		XtManageChild(togg_d4);
2011 		XmStringFree(s_label);
2012 		XtAddCallback(togg_d4, XmNarmCallback, motif_select_disk, (XtPointer) 4);
2013 
2014 		s_label = XmStringCreateSimple("D5:");
2015 		n = 0;
2016 		XtSetArg(args[n], XmNlabelString, s_label);
2017 		n++;
2018 		togg_d5 = XmCreateToggleButtonGadget(rbox_d, "togg_d5", args, n);
2019 		XtManageChild(togg_d5);
2020 		XmStringFree(s_label);
2021 		XtAddCallback(togg_d5, XmNarmCallback, motif_select_disk, (XtPointer) 5);
2022 
2023 		s_label = XmStringCreateSimple("D6:");
2024 		n = 0;
2025 		XtSetArg(args[n], XmNlabelString, s_label);
2026 		n++;
2027 		togg_d6 = XmCreateToggleButtonGadget(rbox_d, "togg_d6", args, n);
2028 		XtManageChild(togg_d6);
2029 		XmStringFree(s_label);
2030 		XtAddCallback(togg_d6, XmNarmCallback, motif_select_disk, (XtPointer) 6);
2031 
2032 		s_label = XmStringCreateSimple("D7:");
2033 		n = 0;
2034 		XtSetArg(args[n], XmNlabelString, s_label);
2035 		n++;
2036 		togg_d7 = XmCreateToggleButtonGadget(rbox_d, "togg_d7", args, n);
2037 		XtManageChild(togg_d7);
2038 		XmStringFree(s_label);
2039 		XtAddCallback(togg_d7, XmNarmCallback, motif_select_disk, (XtPointer) 7);
2040 
2041 		s_label = XmStringCreateSimple("D8:");
2042 		n = 0;
2043 		XtSetArg(args[n], XmNlabelString, s_label);
2044 		n++;
2045 		togg_d8 = XmCreateToggleButtonGadget(rbox_d, "togg_d8", args, n);
2046 		XtManageChild(togg_d8);
2047 		XmStringFree(s_label);
2048 		XtAddCallback(togg_d8, XmNarmCallback, motif_select_disk, (XtPointer) 8);
2049 
2050 
2051 		fsel_r = XmCreateFileSelectionDialog(toplevel, "load_rom", NULL, 0);
2052 		XtAddCallback(fsel_r, XmNokCallback, motif_insert_rom, NULL);
2053 		XtAddCallback(fsel_r, XmNcancelCallback, motif_fs_cancel, NULL);
2054 
2055 		if (UI_n_atari_files_dir > 0) {
2056 			tmpstr = (char *) XtMalloc(strlen(UI_atari_files_dir[0] + 3));
2057 			strcpy(Util_stpcpy(tmpstr, UI_atari_files_dir[0]), "/*");
2058 		}
2059 		else {
2060 			tmpstr = (char *) XtMalloc(4);
2061 			strcpy(tmpstr, "./*");
2062 		}
2063 		xmtmpstr = XmStringCreateSimple(tmpstr);
2064 		XmFileSelectionDoSearch(fsel_b, xmtmpstr);
2065 		XmFileSelectionDoSearch(fsel_d, xmtmpstr);
2066 		XmStringFree(xmtmpstr);
2067 		/* XXX: can use the same tmpstr? can use the same xmtmpstr? */
2068 		xmtmpstr = XmStringCreateSimple(tmpstr);
2069 		XmFileSelectionDoSearch(fsel_r, xmtmpstr);
2070 		XmStringFree(xmtmpstr);
2071 		XtFree(tmpstr);
2072 
2073 		s_d1 = XmStringCreateSimple("D1:");
2074 		s_d2 = XmStringCreateSimple("D2:");
2075 		s_d3 = XmStringCreateSimple("D3:");
2076 		s_d4 = XmStringCreateSimple("D4:");
2077 		s_d5 = XmStringCreateSimple("D5:");
2078 		s_d6 = XmStringCreateSimple("D6:");
2079 		s_d7 = XmStringCreateSimple("D7:");
2080 		s_d8 = XmStringCreateSimple("D8:");
2081 		eject_menu = XmVaCreateSimplePulldownMenu(system_menu,
2082 												  "eject_disk", 2,
2083 												  motif_eject_cback,
2084 								   XmVaPUSHBUTTON, s_d1, '1', NULL, NULL,
2085 								   XmVaPUSHBUTTON, s_d2, '2', NULL, NULL,
2086 								   XmVaPUSHBUTTON, s_d3, '3', NULL, NULL,
2087 								   XmVaPUSHBUTTON, s_d4, '4', NULL, NULL,
2088 								   XmVaPUSHBUTTON, s_d5, '5', NULL, NULL,
2089 								   XmVaPUSHBUTTON, s_d6, '6', NULL, NULL,
2090 								   XmVaPUSHBUTTON, s_d7, '7', NULL, NULL,
2091 								   XmVaPUSHBUTTON, s_d8, '8', NULL, NULL,
2092 												  NULL);
2093 		disable_menu = XmVaCreateSimplePulldownMenu(system_menu,
2094 													"disable_disk", 3,
2095 													motif_disable_cback,
2096 								   XmVaPUSHBUTTON, s_d1, '1', NULL, NULL,
2097 								   XmVaPUSHBUTTON, s_d2, '2', NULL, NULL,
2098 								   XmVaPUSHBUTTON, s_d3, '3', NULL, NULL,
2099 								   XmVaPUSHBUTTON, s_d4, '4', NULL, NULL,
2100 								   XmVaPUSHBUTTON, s_d5, '5', NULL, NULL,
2101 								   XmVaPUSHBUTTON, s_d6, '6', NULL, NULL,
2102 								   XmVaPUSHBUTTON, s_d7, '7', NULL, NULL,
2103 								   XmVaPUSHBUTTON, s_d8, '8', NULL, NULL,
2104 													NULL);
2105 		XmStringFree(s_d1);
2106 		XmStringFree(s_d2);
2107 		XmStringFree(s_d3);
2108 		XmStringFree(s_d4);
2109 		XmStringFree(s_d5);
2110 		XmStringFree(s_d6);
2111 		XmStringFree(s_d7);
2112 		XmStringFree(s_d8);
2113 
2114 		drawing_area = XtVaCreateManagedWidget("Canvas",
2115 										xmDrawingAreaWidgetClass, main_w,
2116 											   XmNunitType, XmPIXELS,
2117 											   XmNheight, window_height,
2118 											   XmNwidth, window_width,
2119 											   XmNresizePolicy, XmNONE,
2120 											   NULL);
2121 
2122 		XtAddEventHandler(drawing_area,
2123 						  KeyPressMask | KeyReleaseMask | VisibilityChangeMask | FocusChangeMask, /* mmm */
2124 						  False,
2125 						  motif_keypress, NULL);
2126 
2127 		XtAddEventHandler(drawing_area,
2128 						  ExposureMask,
2129 						  False,
2130 						  motif_exposure, NULL);
2131 
2132 		XtRealizeWidget(toplevel);
2133 	}
2134 
2135 	display = XtDisplay(drawing_area);
2136 
2137 	window = XtWindow(drawing_area);
2138 
2139 	screen = XDefaultScreenOfDisplay(display);
2140 	if (!screen) {
2141 		printf("Unable to get screen\n");
2142 		exit(1);
2143 	}
2144 	visual = XDefaultVisualOfScreen(screen);
2145 	if (!visual) {
2146 		printf("Unable to get visual\n");
2147 		exit(1);
2148 	}
2149 	depth = XDefaultDepthOfScreen(screen);
2150 	cmap = XDefaultColormapOfScreen(screen);
2151 #endif /* MOTIF */
2152 
2153 #if !defined(XVIEW) && !defined(MOTIF)
2154 	display = XOpenDisplay(NULL);
2155 	if (!display) {
2156 		printf("Failed to open display\n");
2157 		exit(1);
2158 	}
2159 	screen = XDefaultScreenOfDisplay(display);
2160 	if (!screen) {
2161 		printf("Unable to get screen\n");
2162 		exit(1);
2163 	}
2164 	visual = XDefaultVisualOfScreen(screen);
2165 	if (!visual) {
2166 		printf("Unable to get visual\n");
2167 		exit(1);
2168 	}
2169 	depth = XDefaultDepthOfScreen(screen);
2170 
2171 	if (private_cmap)
2172 		cmap = XCreateColormap(display,
2173 							   XRootWindowOfScreen(screen),
2174 							   visual,
2175 							   AllocNone);
2176 	else
2177 		cmap = XDefaultColormapOfScreen(screen);
2178 
2179 	xswda.event_mask = KeyPressMask | KeyReleaseMask | ExposureMask | VisibilityChangeMask | FocusChangeMask /* mmm */;
2180 	xswda.colormap = cmap;
2181 
2182 	window = XCreateWindow(display,
2183 						   XRootWindowOfScreen(screen),
2184 						   50, 50,
2185 						   window_width, window_height, 3, depth,
2186 						   InputOutput, visual,
2187 						   CWEventMask | CWBackPixel | CWColormap,
2188 						   &xswda);
2189 
2190 	XStoreName(display, window, Atari800_TITLE);
2191 #endif /* !defined(XVIEW) && !defined(MOTIF) */
2192 
2193 #ifdef SHM
2194 	{
2195 		int major;
2196 		int minor;
2197 		Bool pixmaps;
2198 		Status status;
2199 		int shmsize;
2200 
2201 		status = XShmQueryVersion(display, &major, &minor, &pixmaps);
2202 		if (!status) {
2203 			printf("X Shared Memory extensions not available\n");
2204 			exit(1);
2205 		}
2206 		printf("Using X11 Shared Memory Extensions\n");
2207 
2208 		image = XShmCreateImage(display, visual, depth, ZPixmap,
2209 						NULL, &shminfo, window_width, window_height);
2210 		shmsize = (window_width * window_height *
2211 					image->bits_per_pixel) / 8;
2212 
2213 		shminfo.shmid = shmget(IPC_PRIVATE, shmsize, IPC_CREAT | 0777);
2214 		shminfo.shmaddr = image->data = shmat(shminfo.shmid, 0, 0);
2215 		shminfo.readOnly = False;
2216 
2217 		XShmAttach(display, &shminfo);
2218 
2219 		XSync(display, False);
2220 
2221 		shmctl(shminfo.shmid, IPC_RMID, 0);
2222 
2223 	}
2224 #else
2225 	pixmap = XCreatePixmap(display, window,
2226 						   window_width, window_height, depth);
2227 #endif /* SHM */
2228 
2229 	if (depth <= 8)
2230 		colorstep = 2;
2231 	else
2232 		colorstep = 1;
2233 	for (i = 0; i < 256; i += colorstep) {
2234 		XColor colour;
2235 
2236 		int rgb = Colours_table[i];
2237 		int status;
2238 
2239 		colour.red = (rgb & 0x00ff0000) >> 8;
2240 		colour.green = (rgb & 0x0000ff00);
2241 		colour.blue = (rgb & 0x000000ff) << 8;
2242 
2243 		status = XAllocColor(display,
2244 							 cmap,
2245 							 &colour);
2246 
2247 		for (j = 0; j < colorstep; j++)
2248 			colours[i + j] = colour.pixel;
2249 
2250 #ifdef SHM
2251 #ifdef USE_COLOUR_TRANSLATION_TABLE
2252 		for (j = 0; j < colorstep; j++)
2253 			colour_translation_table[i + j] = colours[i + j] | (colours[i + j] << 8);
2254 #endif
2255 #endif
2256 	}
2257 
2258 	for (i = 0; i < 256; i++) {
2259 		xgcvl.background = colours[0];
2260 		xgcvl.foreground = colours[i];
2261 
2262 		gc_colour[i] = XCreateGC(display, window,
2263 								 GCForeground | GCBackground,
2264 								 &xgcvl);
2265 	}
2266 
2267 	xgcvl.background = colours[0];
2268 	xgcvl.foreground = colours[0];
2269 
2270 	gc = XCreateGC(display, window,
2271 				   GCForeground | GCBackground,
2272 				   &xgcvl);
2273 
2274 #ifndef SHM
2275 	XFillRectangle(display, pixmap, gc, 0, 0,
2276 				   window_width, window_height);
2277 	for (i = 0; i < NRECTS; i++)
2278 		rectangles[i].height = (windowsize == Huge) ? 3 : 2;
2279 #endif
2280 
2281 	XMapWindow(display, window);
2282 
2283 	XSync(display, False);
2284 	autorepeat_get();
2285 
2286  /*
2287    ============================
2288    Storage for Atari 800 Screen
2289    ============================
2290  */
2291 	image_data = (UBYTE *) Util_malloc(Screen_WIDTH * Screen_HEIGHT);
2292 
2293 	keyboard_consol = INPUT_CONSOL_NONE;
2294 
2295 	if (x11bug) {
2296 		printf("Initial X11 controller configuration\n");
2297 		printf("------------------------------------\n\n");
2298 		printf("Keypad is ");
2299 		Atari_WhatIs(keypad_mode);
2300 		printf("\n");
2301 		printf("Mouse is ");
2302 		Atari_WhatIs(xmouse_mode);
2303 		printf("\n");
2304 		printf("/dev/js0 is ");
2305 		Atari_WhatIs(js0_mode);
2306 		printf("\n");
2307 		printf("/dev/js1 is ");
2308 		Atari_WhatIs(js1_mode);
2309 		printf("\n");
2310 	}
2311 	signal(SIGSEGV, segmentationfault);
2312 
2313 	return TRUE;
2314 }
2315 
PLATFORM_Exit(int run_monitor)2316 int PLATFORM_Exit(int run_monitor)
2317 {
2318 	int restart;
2319 
2320 	Log_flushlog();
2321 	if (run_monitor) {
2322 		autorepeat_restore();
2323 		restart = MONITOR_Run();
2324 		autorepeat_off();
2325 	}
2326 	else
2327 		restart = FALSE;
2328 
2329 	if (!restart) {
2330 		if (image_data != NULL)
2331 			free(image_data);
2332 
2333 		if (display != NULL) {
2334 			XSync(display, True);
2335 
2336 			if (private_cmap)
2337 				XFreeColormap(display, cmap);
2338 
2339 #ifdef SHM
2340 			if (image != NULL)
2341 				XDestroyImage(image);
2342 #else
2343 			XFreePixmap(display, pixmap);
2344 #endif
2345 			XUnmapWindow(display, window);
2346 			XDestroyWindow(display, window);
2347 			autorepeat_restore();
2348 			XCloseDisplay(display);
2349 		}
2350 
2351 #ifdef LINUX_JOYSTICK
2352 		if (js0 != -1)
2353 			close(js0);
2354 
2355 		if (js1 != -1)
2356 			close(js1);
2357 #endif
2358 
2359 	}
2360 	return restart;
2361 }
2362 
PLATFORM_DisplayScreen(void)2363 void PLATFORM_DisplayScreen(void)
2364 {
2365 	static char status_line[64];
2366 	int update_status_line = FALSE;
2367 
2368 	if (!invisible) {
2369 		const UBYTE *ptr2 = (const UBYTE *) Screen_atari + clipping_y * Screen_WIDTH + clipping_x;
2370 
2371 #ifdef SHM
2372 
2373 		int first_x = Screen_WIDTH;
2374 		int last_x = -1000;
2375 		int first_y = Screen_HEIGHT;
2376 		int last_y = -1000;
2377 		int x;
2378 		int y;
2379 
2380 #define SHM_SET_LAST \
2381 		last_y = y; \
2382 		if (x > last_x) \
2383 			last_x = x; \
2384 		if (x < first_x) \
2385 			first_x = x;
2386 
2387 #define SHM_DISPLAY_SCREEN(pixel_type) \
2388 			pixel_type *ptr = (pixel_type *) image->data; \
2389 			pixel_type help_color; \
2390 			if (windowsize == Small) { \
2391 				for (y = clipping_y; y < (clipping_y + clipping_height); y++) { \
2392 					for (x = clipping_x; x < (clipping_x + clipping_width); x++) { \
2393 						help_color = colours[*ptr2++]; \
2394 						if (help_color != *ptr) { \
2395 							SHM_SET_LAST \
2396 							*ptr = help_color; \
2397 						} \
2398 						ptr++; \
2399 					} \
2400 					if (first_y > last_y && last_y >= 0) \
2401 						first_y = last_y; \
2402 					ptr2 += Screen_WIDTH - clipping_width; \
2403 				} \
2404 			} \
2405 			else if (windowsize == Large) { \
2406 				for (y = clipping_y; y < (clipping_y + clipping_height); y++) { \
2407 					pixel_type *ptr_second_line = ptr + window_width; \
2408 					for (x = clipping_x; x < (clipping_x + clipping_width); x++) { \
2409 						help_color = colours[*ptr2++]; \
2410 						if (help_color != *ptr) { \
2411 							SHM_SET_LAST \
2412 							ptr[0] = help_color; \
2413 							ptr[1] = help_color; \
2414 							ptr_second_line[0] = help_color; \
2415 							ptr_second_line[1] = help_color; \
2416 						} \
2417 						ptr += 2; \
2418 						ptr_second_line += 2; \
2419 					} \
2420 					if (first_y > last_y && last_y >= 0) \
2421 						first_y = last_y; \
2422 					ptr2 += Screen_WIDTH - clipping_width; \
2423 					ptr += window_width; \
2424 				} \
2425 			} \
2426 			else { \
2427 				for (y = clipping_y; y < (clipping_y + clipping_height); y++) { \
2428 					pixel_type *ptr_second_line = ptr + window_width; \
2429 					pixel_type *ptr_third_line = ptr + window_width + window_width; \
2430 					for (x = clipping_x; x < (clipping_x + clipping_width); x++) { \
2431 						help_color = colours[*ptr2++]; \
2432 						if (help_color != *ptr) { \
2433 							SHM_SET_LAST \
2434 							ptr[0] = help_color; \
2435 							ptr[1] = help_color; \
2436 							ptr[2] = help_color; \
2437 							ptr_second_line[0] = help_color; \
2438 							ptr_second_line[1] = help_color; \
2439 							ptr_second_line[2] = help_color; \
2440 							ptr_third_line[0] = help_color; \
2441 							ptr_third_line[1] = help_color; \
2442 							ptr_third_line[2] = help_color; \
2443 						} \
2444 						ptr += 3; \
2445 						ptr_second_line += 3; \
2446 						ptr_third_line += 3; \
2447 					} \
2448 					if (first_y > last_y && last_y >= 0) \
2449 						first_y = last_y; \
2450 					ptr2 += Screen_WIDTH - clipping_width; \
2451 					ptr += window_width + window_width; \
2452 				} \
2453 			}
2454 
2455 		if (image->bits_per_pixel == 32) {
2456 			SHM_DISPLAY_SCREEN(ULONG)
2457 		}
2458 		else if (image->bits_per_pixel == 16) {
2459 			SHM_DISPLAY_SCREEN(UWORD)
2460 		}
2461 		else if (image->bits_per_pixel == 8) {
2462 			SHM_DISPLAY_SCREEN(UBYTE)
2463 		}
2464 
2465 		if (modified) {
2466 			XShmPutImage(display, window, gc, image, 0, 0, 0, 0,
2467 					 window_width, window_height, 0);
2468 			modified = FALSE;
2469 		}
2470 		else if (last_y >= 0) {
2471 			last_x++;
2472 			last_y++;
2473 			if (first_x < clipping_x)
2474 				first_x = clipping_x;
2475 			if (last_x > clipping_x + clipping_width)
2476 				last_x = clipping_x + clipping_width;
2477 			else if (last_x <= first_x)
2478 				last_x = first_x + 1;
2479 			if (first_y < clipping_y)
2480 				first_y = clipping_y;
2481 			if (last_y > clipping_y + clipping_height)
2482 				last_y = clipping_y + clipping_height;
2483 			else if (last_y <= first_y)
2484 				last_y = first_y + 1;
2485 
2486 			first_x *= clipping_factor;
2487 			last_x *= clipping_factor;
2488 			first_y *= clipping_factor;
2489 			last_y *= clipping_factor;
2490 
2491 			XShmPutImage(display, window, gc, image,
2492 					 first_x - (clipping_x * clipping_factor),
2493 					 first_y - (clipping_y * clipping_factor),
2494 					 first_x - (clipping_x * clipping_factor),
2495 					 first_y - (clipping_y * clipping_factor),
2496 					 last_x - first_x, last_y - first_y, 0);
2497 		}
2498 
2499 		XSync(display, FALSE);
2500 
2501 #else /* SHM */
2502 
2503 		UBYTE *ptr = image_data + clipping_y * Screen_WIDTH + clipping_x;
2504 		int n = 0;
2505 		int last_colour = -1;
2506 		int x;
2507 		int y;
2508 
2509 		switch (windowsize) {
2510 		case Small:
2511 			for (y = 0; y < clipping_height; y++) {
2512 				for (x = 0; x < clipping_width; x++) {
2513 					UBYTE colour = *ptr2++;
2514 					if (colour != *ptr) {
2515 						*ptr = colour;
2516 						if (colour != last_colour || n >= NPOINTS) {
2517 							if (n > 0) {
2518 								XDrawPoints(display, pixmap, gc_colour[last_colour],
2519 											points, n, CoordModeOrigin);
2520 								n = 0;
2521 								modified = TRUE;
2522 							}
2523 							last_colour = colour;
2524 						}
2525 						points[n].x = x;
2526 						points[n].y = y;
2527 						n++;
2528 					}
2529 					ptr++;
2530 				}
2531 				ptr += Screen_WIDTH - clipping_width;
2532 				ptr2 += Screen_WIDTH - clipping_width;
2533 			}
2534 			if (n > 0) {
2535 				XDrawPoints(display, pixmap, gc_colour[last_colour],
2536 							points, n, CoordModeOrigin);
2537 				modified = TRUE;
2538 			}
2539 			break;
2540 		case Large:
2541 			for (y = 0; y < window_height; y += 2) {
2542 				for (x = 0; x < window_width; ) {
2543 					UBYTE colour = *ptr2++;
2544 					if (colour != *ptr) {
2545 						int width = 2;
2546 						*ptr++ = colour;
2547 						if (colour != last_colour || n >= NRECTS) {
2548 							if (n > 0) {
2549 								XFillRectangles(display, pixmap, gc_colour[last_colour],
2550 												rectangles, n);
2551 								n = 0;
2552 								modified = TRUE;
2553 							}
2554 							last_colour = colour;
2555 						}
2556 						rectangles[n].x = x;
2557 						rectangles[n].y = y;
2558 						while ((x += 2) < window_width && colour == *ptr2 && colour != *ptr) {
2559 							width += 2;
2560 							ptr2++;
2561 							*ptr++ = colour;
2562 						}
2563 						rectangles[n].width = width;
2564 						/* rectangles[n].height = 2; */
2565 						n++;
2566 						continue;
2567 					}
2568 					ptr++;
2569 					x += 2;
2570 				}
2571 				ptr += Screen_WIDTH - clipping_width;
2572 				ptr2 += Screen_WIDTH - clipping_width;
2573 			}
2574 			if (n > 0) {
2575 				XFillRectangles(display, pixmap, gc_colour[last_colour],
2576 								rectangles, n);
2577 				modified = TRUE;
2578 			}
2579 			break;
2580 		case Huge:
2581 			for (y = 0; y < window_height; y += 3) {
2582 				for (x = 0; x < window_width; ) {
2583 					UBYTE colour = *ptr2++;
2584 					if (colour != *ptr) {
2585 						int width = 3;
2586 						*ptr++ = colour;
2587 						if (colour != last_colour || n >= NRECTS) {
2588 							if (n > 0) {
2589 								XFillRectangles(display, pixmap, gc_colour[last_colour],
2590 												rectangles, n);
2591 								n = 0;
2592 								modified = TRUE;
2593 							}
2594 							last_colour = colour;
2595 						}
2596 						rectangles[n].x = x;
2597 						rectangles[n].y = y;
2598 						while ((x += 3) < window_width && colour == *ptr2 && colour != *ptr) {
2599 							width += 3;
2600 							ptr2++;
2601 							*ptr++ = colour;
2602 						}
2603 						rectangles[n].width = width;
2604 						/* rectangles[n].height = 3; */
2605 						n++;
2606 						continue;
2607 					}
2608 					ptr++;
2609 					x += 3;
2610 				}
2611 				ptr2 += Screen_WIDTH - clipping_width;
2612 				ptr += Screen_WIDTH - clipping_width;
2613 			}
2614 			if (n > 0) {
2615 				XFillRectangles(display, pixmap, gc_colour[last_colour],
2616 								rectangles, n);
2617 				modified = TRUE;
2618 			}
2619 			break;
2620 		}
2621 
2622 		if (modified) {
2623 			XCopyArea(display, pixmap, window, gc, 0, 0,
2624 					  window_width, window_height, 0, 0);
2625 			XSync(display, FALSE);
2626 			modified = FALSE;
2627 		}
2628 
2629 #endif /* SHM */
2630 
2631 	}
2632 
2633 	switch (x11_monitor) {
2634 	case MONITOR_SIO:
2635 		if (SIO_status[0] != '\0') {
2636 #ifdef XVIEW
2637 			strcpy(status_line, SIO_status);
2638 #else
2639 			sprintf(status_line, "%s - %s",
2640 					Atari800_TITLE, SIO_status);
2641 #endif
2642 			SIO_status[0] = '\0';
2643 			update_status_line = TRUE;
2644 		}
2645 		else {
2646 			update_status_line = FALSE;
2647 		}
2648 		break;
2649 	default:
2650 		update_status_line = FALSE;
2651 		break;
2652 	}
2653 
2654 	if (update_status_line) {
2655 #ifdef XVIEW
2656 		xv_set(frame,
2657 			   FRAME_LEFT_FOOTER, status_line,
2658 			   NULL);
2659 #else
2660 #ifdef MOTIF
2661 		XtVaSetValues(toplevel,
2662 					  XtNtitle, status_line,
2663 					  NULL);
2664 #else
2665 		XStoreName(display, window, status_line);
2666 #endif
2667 #endif
2668 	}
2669 
2670 }
2671 
PLATFORM_Keyboard(void)2672 int PLATFORM_Keyboard(void)
2673 {
2674 	static int keycode = AKEY_NONE;
2675 
2676 #ifdef XVIEW
2677 	notify_dispatch();
2678 	XFlush(display);
2679 #endif
2680 
2681 #ifdef MOTIF
2682 	while (XtAppPending(app)) {
2683 		static XEvent event;
2684 
2685 		XtAppNextEvent(app, &event);
2686 		XtDispatchEvent(&event);
2687 	}
2688 #endif
2689 
2690 #if defined(XVIEW) || defined(MOTIF)
2691 	keycode = xview_keycode;
2692 #else
2693 	if (XEventsQueued(display, QueuedAfterFlush) > 0) {
2694 		XEvent event;
2695 
2696 		XNextEvent(display, &event);
2697 		keycode = GetKeyCode(&event);
2698 	}
2699 #endif
2700 
2701 	return keycode;
2702 }
2703 
2704 #if 0
2705 void experimental_mouse_joystick(int mode)	/* Don't use ;-) */
2706 {
2707 	Window root_return;
2708 	Window child_return;
2709 	int root_x_return;
2710 	int root_y_return;
2711 	int win_x_return;
2712 	int win_y_return;
2713 	int mask_return;
2714 
2715 	static int prev_x=-1,prev_y=-1;
2716 
2717 	XQueryPointer(display, window, &root_return, &child_return,
2718 				  &root_x_return, &root_y_return,
2719 				  &win_x_return, &win_y_return,
2720 				  &mask_return);
2721 
2722 	if (mode < 5) {
2723 		int dx,dy;
2724 		int course,rc;
2725 
2726 		if( prev_x<0 )	prev_x=root_x_return;
2727 		if( prev_y<0 )	prev_y=root_y_return;
2728 		dx=(root_x_return-prev_x)<<1;
2729 		dy=(root_y_return-prev_y)*3;
2730 #define Ms	8
2731 #define Mc	3	/* Mc/Mm = 2 45 deg.  <2 => >45 deg for x or y only */
2732 #define Mm	2
2733 		if( dx>Ms && dy>Ms )
2734 		{	if( dx*Mm>Mc*dy )
2735 				course = 0x08; /* RIGHT */
2736 			else if ( dx*Mc<dy*Mm )
2737 				course = 0x02; /* DOWN */
2738 			else	course = 0x0a; /* RIGHT DOWN */
2739 		} else if( dx<-Ms && dy<-Ms )
2740 		{	if( dx*Mm<Mc*dy )
2741 				course = 0x04; /* LEFT */
2742 			else if ( dx*Mc>dy*Mm )
2743 				course = 0x01; /* UP */
2744 			else	course = 0x05; /* LEFT UP */
2745 		} else if( dx<-Ms && dy>Ms )
2746 		{	if( -dx*Mm>Mc*dy )
2747 				course = 0x04; /* LEFT */
2748 			else if ( -dx*Mc<dy*Mm )
2749 				course = 0x02; /* DOWN */
2750 			else	course = 0x06; /* LEFT DOWN */
2751 		} else if( dx>Ms && dy<-Ms )
2752 		{	if( -dx*Mm<Mc*dy )
2753 				course = 0x08; /* RIGHT */
2754 			else if ( -dx*Mc>dy*Mm )
2755 				course = 0x01; /* UP */
2756 			else	course = 0x09; /* RIGHT UP */
2757 		}
2758 		else if( dx>Ms )
2759 				course = 0x08; /* RIGHT */
2760 		else if( dx<-Ms )
2761 				course = 0x04; /* LEFT */
2762 		else if( dy>Ms )
2763 				course = 0x02; /* DOWN */
2764 		else if( dy<-Ms )
2765 				course = 0x01; /* UP */
2766 		else	course=0;
2767 
2768 		rc=(((course&0x5)<<1)|((course&0xa)>>1));
2769 		rc&= ~mouse_stick;
2770 		mouse_stick|=rc;
2771 		course&=~(((rc&0x5)<<1)|((rc&0xa)>>1));
2772 		mouse_stick&=~course;
2773 
2774 		prev_x=root_x_return;
2775 		prev_y=root_y_return;
2776 	}
2777 	else {
2778 		if (mask_return)
2779 			mouse_stick &= 0xfb;
2780 	}
2781 }
2782 #endif
2783 
mouse_joystick(int mode)2784 static void mouse_joystick(int mode)
2785 {
2786 	Window root_return;
2787 	Window child_return;
2788 	int root_x_return;
2789 	int root_y_return;
2790 	int win_x_return;
2791 	int win_y_return;
2792 	unsigned int mask_return;
2793 
2794 	mouse_stick = 0x0f;
2795 
2796 	XQueryPointer(display, window, &root_return, &child_return,
2797 				  &root_x_return, &root_y_return,
2798 				  &win_x_return, &win_y_return,
2799 				  &mask_return);
2800 
2801 	if (mode < 5) {
2802 		int center_x;
2803 		int center_y;
2804 		int threshold;
2805 
2806 		if (windowsize == Small) {
2807 			center_x = window_width / 2;
2808 			center_y = window_height / 2;
2809 			threshold = 32;
2810 		}
2811 		else if (windowsize == Large) {
2812 			center_x = window_width / 2;
2813 			center_y = window_height / 2;
2814 			threshold = 64;
2815 		}
2816 		else {
2817 			center_x = window_width / 2;
2818 			center_y = window_height / 2;
2819 			threshold = 96;
2820 		}
2821 
2822 		if (win_x_return < 0 || win_x_return > center_x * 2 ||
2823 		    win_y_return < 0 || win_y_return > center_y * 2 )
2824 			mouse_stick = 0x0f;
2825 		else
2826 		{
2827 		if (win_x_return < (center_x - threshold))
2828 			mouse_stick &= 0xfb;
2829 		if (win_x_return > (center_x + threshold))
2830 			mouse_stick &= 0xf7;
2831 		if (win_y_return < (center_y - threshold))
2832 			mouse_stick &= 0xfe;
2833 		if (win_y_return > (center_y + threshold))
2834 			mouse_stick &= 0xfd;
2835 		}
2836 	}
2837 	else {
2838 		if (mask_return)
2839 			mouse_stick &= 0xfb;
2840 	}
2841 }
2842 
2843 #ifdef LINUX_JOYSTICK
2844 
read_joystick(int js,int centre_x,int centre_y)2845 static void read_joystick(int js, int centre_x, int centre_y)
2846 {
2847 	const int threshold = 50;
2848 	int status;
2849 
2850 	mouse_stick = 0x0f;
2851 
2852 	status = read(js, &js_data, JS_RETURN);
2853 	if (status != JS_RETURN) {
2854 		perror("/dev/js");
2855 		exit(1);
2856 	}
2857 	if (js_data.x < (centre_x - threshold))
2858 		mouse_stick &= 0xfb;
2859 	if (js_data.x > (centre_x + threshold))
2860 		mouse_stick &= 0xf7;
2861 	if (js_data.y < (centre_y - threshold))
2862 		mouse_stick &= 0xfe;
2863 	if (js_data.y > (centre_y + threshold))
2864 		mouse_stick &= 0xfd;
2865 }
2866 #endif
2867 
PLATFORM_PORT(int num)2868 int PLATFORM_PORT(int num)
2869 {
2870 	int nibble_0 = 0x0f;
2871 	int nibble_1 = 0x0f;
2872 
2873 	if (num == 0) {
2874 		if (keypad_mode == 0)
2875 			nibble_0 = keypad_stick;
2876 		else if (keypad_mode == 1)
2877 			nibble_1 = keypad_stick;
2878 
2879 		if (INPUT_mouse_mode == INPUT_MOUSE_OFF) {
2880 			if (xmouse_mode == 0) {
2881 				mouse_joystick(xmouse_mode);
2882 				nibble_0 = mouse_stick;
2883 			}
2884 			else if (xmouse_mode == 1) {
2885 				mouse_joystick(xmouse_mode);
2886 				nibble_1 = mouse_stick;
2887 			}
2888 		}
2889 #ifdef LINUX_JOYSTICK
2890 		if (js0_mode == 0) {
2891 			read_joystick(js0, js0_centre_x, js0_centre_y);
2892 			nibble_0 = mouse_stick;
2893 		}
2894 		else if (js0_mode == 1) {
2895 			read_joystick(js0, js0_centre_x, js0_centre_y);
2896 			nibble_1 = mouse_stick;
2897 		}
2898 		if (js1_mode == 0) {
2899 			read_joystick(js1, js1_centre_x, js1_centre_y);
2900 			nibble_0 = mouse_stick;
2901 		}
2902 		else if (js1_mode == 1) {
2903 			read_joystick(js1, js1_centre_x, js1_centre_y);
2904 			nibble_1 = mouse_stick;
2905 		}
2906 #endif
2907 	}
2908 	else {
2909 		if (keypad_mode == 2)
2910 			nibble_0 = keypad_stick;
2911 		else if (keypad_mode == 3)
2912 			nibble_1 = keypad_stick;
2913 
2914 		if (INPUT_mouse_mode == INPUT_MOUSE_OFF) {
2915 			if (xmouse_mode == 2) {
2916 				mouse_joystick(xmouse_mode);
2917 				nibble_0 = mouse_stick;
2918 			}
2919 			else if (xmouse_mode == 3) {
2920 				mouse_joystick(xmouse_mode);
2921 				nibble_1 = mouse_stick;
2922 			}
2923 		}
2924 
2925 #ifdef LINUX_JOYSTICK
2926 		if (js0_mode == 2) {
2927 			read_joystick(js0, js0_centre_x, js0_centre_y);
2928 			nibble_0 = mouse_stick;
2929 		}
2930 		else if (js0_mode == 3) {
2931 			read_joystick(js0, js0_centre_x, js0_centre_y);
2932 			nibble_1 = mouse_stick;
2933 		}
2934 		if (js1_mode == 2) {
2935 			read_joystick(js1, js1_centre_x, js1_centre_y);
2936 			nibble_0 = mouse_stick;
2937 		}
2938 		else if (js1_mode == 3) {
2939 			read_joystick(js1, js1_centre_x, js1_centre_y);
2940 			nibble_1 = mouse_stick;
2941 		}
2942 #endif
2943 	}
2944 
2945 	return (nibble_1 << 4) | nibble_0;
2946 }
2947 
PLATFORM_TRIG(int num)2948 int PLATFORM_TRIG(int num)
2949 {
2950 	int trig = 1;				/* Trigger not pressed */
2951 
2952 	if (num == keypad_mode) {
2953 		trig = keypad_trig;
2954 	}
2955 	if (num == xmouse_mode) {
2956 		Window root_return;
2957 		Window child_return;
2958 		int root_x_return;
2959 		int root_y_return;
2960 		int win_x_return;
2961 		int win_y_return;
2962 		unsigned int mask_return;
2963 
2964 		if (XQueryPointer(display, window, &root_return, &child_return,
2965 						  &root_x_return, &root_y_return,
2966 						  &win_x_return, &win_y_return,
2967 						  &mask_return)) {
2968 			if (win_x_return < 0 || win_x_return > window_width ||
2969 			    win_y_return < 0 || win_y_return > window_height)
2970 				trig = 1;
2971 			else if (mask_return & Button1Mask)
2972 				trig = 0;
2973 		}
2974 	}
2975 #ifdef LINUX_JOYSTICK
2976 	if (num == js0_mode) {
2977 		int status;
2978 
2979 		status = read(js0, &js_data, JS_RETURN);
2980 		if (status != JS_RETURN) {
2981 			perror("/dev/js0");
2982 			exit(1);
2983 		}
2984 		if (js_data.buttons & 0x01)
2985 			trig = 0;
2986 		else
2987 			trig = 1;
2988 	}
2989 	if (num == js1_mode) {
2990 		int status;
2991 
2992 		status = read(js1, &js_data, JS_RETURN);
2993 		if (status != JS_RETURN) {
2994 			perror("/dev/js1");
2995 			exit(1);
2996 		}
2997 		trig = (js_data.buttons & 0x0f) ? 0 : 1;
2998 	}
2999 #endif
3000 
3001 	return trig;
3002 }
3003 
Atari_Mouse(void)3004 void Atari_Mouse(void)
3005 {
3006 	static int last_x = 0;
3007 	static int last_y = 0;
3008 	Window root_return;
3009 	Window child_return;
3010 	int root_x_return;
3011 	int root_y_return;
3012 	int win_x_return;
3013 	int win_y_return;
3014 	unsigned int mask_return;
3015 
3016 	if (INPUT_mouse_mode == INPUT_MOUSE_OFF)
3017 		return;
3018 	if (XQueryPointer(display, window, &root_return,
3019 					  &child_return, &root_x_return, &root_y_return,
3020 					  &win_x_return, &win_y_return, &mask_return)) {
3021 		if(INPUT_direct_mouse) {
3022 			int potx = win_x_return, poty = win_y_return;
3023 			if(potx < 0) potx = 0;
3024 			if(poty < 0) poty = 0;
3025 			potx = (double)potx * (228.0 / (double)window_width);
3026 			poty = (double)poty * (228.0 / (double)window_height);
3027 			if(potx > 227) potx = 227;
3028 			if(poty > 227) poty = 227;
3029 			POKEY_POT_input[INPUT_mouse_port << 1] = 227 - potx;
3030 			POKEY_POT_input[(INPUT_mouse_port << 1) + 1] = 227 - poty;
3031 		} else {
3032 			INPUT_mouse_delta_x = win_x_return - last_x;
3033 			INPUT_mouse_delta_y = win_y_return - last_y;
3034 			last_x = win_x_return;
3035 			last_y = win_y_return;
3036 		}
3037 
3038 		INPUT_mouse_buttons = (mask_return & Button1Mask ? 1 : 0)
3039 		              | (mask_return & Button3Mask ? 2 : 0)
3040 		              | (mask_return & Button2Mask ? 4 : 0);
3041 	}
3042 }
3043 
main(int argc,char ** argv)3044 int main(int argc, char **argv)
3045 {
3046 	/* initialise Atari800 core */
3047 	if (!Atari800_Initialise(&argc, argv))
3048 		return 3;
3049 
3050 	/* main loop */
3051 	for (;;) {
3052 		INPUT_key_code = PLATFORM_Keyboard();
3053 
3054 		if (menu_consol != INPUT_CONSOL_NONE) {
3055 			INPUT_key_consol = menu_consol;
3056 			menu_consol = INPUT_CONSOL_NONE;
3057 		}
3058 		else
3059 			INPUT_key_consol = keyboard_consol;
3060 
3061 		Atari_Mouse();
3062 
3063 		Atari800_Frame();
3064 		if (Atari800_display_screen)
3065 			PLATFORM_DisplayScreen();
3066 	}
3067 }
3068