1  /*
2   * UAE - The Un*x Amiga Emulator
3   *
4   * X interface
5   *
6   * Copyright 1995, 1996 Bernd Schmidt
7   * Copyright 1996 Ed Hanway, Andre Beck, Samuel Devulder, Bruno Coste
8   * Copyright 1998 Marcus Sundberg
9   * DGA support by Kai Kollmorgen
10   * X11/DGA merge, hotkeys and grabmouse by Marcus Sundberg
11   * Copyright 2003-2007 Richard Drummond
12   */
13 
14 #include "sysconfig.h"
15 #include "sysdeps.h"
16 
17 #include <X11/Xlib.h>
18 #include <X11/Xutil.h>
19 #include <X11/keysym.h>
20 #include <X11/cursorfont.h>
21 
22 #include <ctype.h>
23 
24 #include "cfgfile.h"
25 #include "uae.h"
26 #include "memory_uae.h"
27 #include "xwin.h"
28 #include "custom.h"
29 #include "drawing.h"
30 #include "newcpu.h"
31 #include "keyboard.h"
32 #include "keybuf.h"
33 #include "gui.h"
34 #include "debug.h"
35 #include "picasso96.h"
36 #include "inputdevice.h"
37 #include "hotkeys.h"
38 #include "keymap/keymap.h"
39 #include "keymap/keymap_all.h"
40 
41 #ifdef __cplusplus
42 #define VI_CLASS c_class
43 #else
44 #define VI_CLASS class
45 #endif
46 
47 #ifdef USE_DGA_EXTENSION
48 
49 #ifdef USE_VIDMODE_EXTENSION
50 #include <X11/extensions/xf86vmode.h>
51 #define VidMode_MINMAJOR 0
52 #define VidMode_MINMINOR 0
53 #endif
54 
55 #include <X11/extensions/Xxf86dga.h>
56 #define DGA_MINMAJOR 0
57 #define DGA_MINMINOR 0
58 
59 #endif /* USE_DGA_EXTENSION */
60 
61 #if SHM_SUPPORT_LINKS == 1
62 
63 #include <sys/ipc.h>
64 #include <sys/shm.h>
65 #include <X11/extensions/XShm.h>
66 
67 #define DO_PUTIMAGE(IMG, SRCX, SRCY, DSTX, DSTY, WIDTH, HEIGHT) \
68     do { \
69 	if (currprefs.x11_use_mitshm && shmavail) \
70 	     XShmPutImage (display, mywin, mygc, (IMG), (SRCX), (SRCY), (DSTX), (DSTY), (WIDTH), (HEIGHT), 0); \
71 	else \
72 	    XPutImage (display, mywin, mygc, (IMG), (SRCX), (SRCY), (DSTX), (DSTY), (WIDTH), (HEIGHT)); \
73     } while (0)
74 #else
75 #define DO_PUTIMAGE(IMG, SRCX, SRCY, DSTX, DSTY, WIDTH, HEIGHT) \
76     XPutImage (display, mywin, mygc, (IMG), (SRCX), (SRCY), (DSTX), (DSTY), (WIDTH), (HEIGHT))
77 #endif
78 
79 /* internal types */
80 struct disp_info {
81     XImage *ximg;
82     char *image_mem;
83 #if SHM_SUPPORT_LINKS == 1
84     XShmSegmentInfo shminfo;
85 #endif
86 };
87 
88 
89 /* internal members */
90 static Display *display;
91 static int screen;
92 static Window rootwin, mywin;
93 static Atom delete_win;
94 
95 static GC mygc;
96 static XColor black, white;
97 static Colormap cmap, cmap2;
98 static int red_bits, green_bits, blue_bits;
99 static int red_shift, green_shift, blue_shift;
100 
101 #ifdef USE_DGA_EXTENSION
102 /* Kludge-O-Matic.
103  * Unfortunately the X server loses colormap changes in DGA mode. Switching
104  * back and forth between two identical colormaps fixes this problem.  */
105 static int dga_colormap_installed;
106 #endif
107 
108 static int need_dither;
109 
110 extern int screen_is_picasso;
111 static char picasso_invalid_lines[1201];
112 static int picasso_has_invalid_lines;
113 static int picasso_invalid_start, picasso_invalid_stop;
114 static int picasso_maxw = 0, picasso_maxh = 0;
115 
116 static int autorepeatoff = 0;
117 static struct disp_info ami_dinfo, pic_dinfo;
118 static Visual *vis;
119 static XVisualInfo visualInfo;
120 static int bitdepth, bit_unit;
121 static Cursor blankCursor, xhairCursor;
122 static int cursorOn;
123 static int inverse_byte_order = 0;
124 
125 static int current_width, current_height;
126 
127 static int x11_init_ok;
128 static int dgaavail = 0, vidmodeavail = 0, shmavail = 0;
129 static int dgamode;
130 static int grabbed;
131 static int mousehack;
132 
133 static int rawkeys_available;
134 static struct uae_input_device_kbr_default *raw_keyboard;
135 
136 void toggle_mousegrab (void);
137 int xkeysym2amiga (int);
138 struct uae_hotkeyseq *get_x11_default_hotkeys (void);
139 const char *get_xkb_keycodes (Display *display);
140 
141 static int oldx, oldy;
142 static int inwindow;
143 
144 #define EVENTMASK (KeyPressMask|KeyReleaseMask|ButtonPressMask \
145 		   |ButtonReleaseMask|PointerMotionMask \
146 		   |FocusChangeMask|EnterWindowMask \
147 		   |ExposureMask |LeaveWindowMask)
148 #define DGA_EVENTMASK (KeyPressMask|KeyReleaseMask|ButtonPressMask \
149 		       |ButtonReleaseMask|PointerMotionMask)
150 
151 #if SHM_SUPPORT_LINKS == 1
152 /* Hack to detect shm-failure, probably due to displaying on a
153  * remote server. */
154 static int shmerror;
155 
156 
157 /* internal prototypes */
158 int mousehack_allowed (void);
159 void setmaintitle(void);
160 void gfx_save_options (FILE *, const struct uae_prefs *);
161 int gfx_parse_option (struct uae_prefs *, const char *, const char *);
162 void gfx_default_options (struct uae_prefs *);
163 int is_vsync (void);
164 void gfx_save_options (FILE *, const struct uae_prefs *);
165 int gfx_parse_option (struct uae_prefs *, const char *, const char *);
166 void gfx_default_options (struct uae_prefs *);
167 static int (*oldshmerrorhandler) (Display *, XErrorEvent *);
168 
169 
170 /* implementations */
shmerrorhandler(Display * dsp,XErrorEvent * ev)171 static int shmerrorhandler (Display *dsp, XErrorEvent *ev)
172 {
173     if (ev->error_code == BadAccess)
174 	shmerror=1;
175     else
176 	(*oldshmerrorhandler) (dsp, ev);
177     return 0;
178 }
179 #endif
180 
get_image(int w,int h,struct disp_info * dispi)181 static void get_image (int w, int h, struct disp_info *dispi)
182 {
183     XImage *new_img;
184     char *p;
185 
186 #if SHM_SUPPORT_LINKS == 1
187     if (currprefs.x11_use_mitshm && shmavail) {
188 	XShmSegmentInfo *shminfo = &dispi->shminfo;
189 
190 	new_img = XShmCreateImage (display, vis, bitdepth, ZPixmap, 0, shminfo, w, h);
191 
192 	shminfo->shmid = shmget (IPC_PRIVATE, h * new_img->bytes_per_line,
193 				 IPC_CREAT | 0777);
194 	shminfo->shmaddr = new_img->data = (char *)shmat (shminfo->shmid, 0, 0);
195 	dispi->image_mem = new_img->data;
196 	shminfo->readOnly = False;
197 	/* Try to let the Xserver attach */
198 	shmerror = 0;
199 	oldshmerrorhandler = XSetErrorHandler (shmerrorhandler);
200 	XShmAttach (display, shminfo);
201 	XSync (display, 0);
202 	XSetErrorHandler (oldshmerrorhandler);
203 	if (shmerror) {
204 	    shmdt (shminfo->shmaddr);
205 	    XDestroyImage (new_img);
206 	    shminfo->shmid = -1;
207 	    shmavail = 0;
208 	    write_log ("MIT-SHM extension failed, trying fallback.\n");
209 	} else {
210 	    /* now deleting means making it temporary */
211 	    shmctl (shminfo->shmid, IPC_RMID, 0);
212 	    dispi->ximg = new_img;
213 	    write_log ("Using MIT-SHM extension.\n");
214 	    return;
215 	}
216     }
217 #endif
218 
219     /* Question for people who know about X: Could we allocate the buffer
220      * after creating the image and then do new_img->data = buffer, as above in
221      * the SHM case?
222      */
223     write_log ("Using normal image buffer.\n");
224     p = (char *)xmalloc (char, h * w * ((bit_unit + 7) / 8)); /* ??? */
225     new_img = XCreateImage (display, vis, bitdepth, ZPixmap, 0, p,
226 			    w, h, 32, 0);
227     if (new_img->bytes_per_line != w * ((bit_unit + 7) / 8))
228 	write_log ("Possible bug here... graphics may look strange.\n");
229 
230     dispi->image_mem = p;
231     dispi->ximg = new_img;
232 }
233 
get_best_visual(Display * display,int screen,XVisualInfo * vi)234 static int get_best_visual (Display *display, int screen, XVisualInfo *vi)
235 {
236     /* try for a 12 bit visual first, then a 16 bit, then a 24 bit, then 8 bit */
237     if (XMatchVisualInfo (display, screen, 12, TrueColor, vi)) {
238     } else if (XMatchVisualInfo (display, screen, 15, TrueColor,   vi)) {
239     } else if (XMatchVisualInfo (display, screen, 16, TrueColor,   vi)) {
240     } else if (XMatchVisualInfo (display, screen, 24, TrueColor,   vi)) {
241     } else if (XMatchVisualInfo (display, screen, 32, TrueColor,   vi)) {
242     } else if (XMatchVisualInfo (display, screen, 8,  PseudoColor, vi)) {
243 	/* for our HP boxes */
244     } else if (XMatchVisualInfo (display, screen, 8,  GrayScale,   vi)) {
245     } else if (XMatchVisualInfo (display, screen, 4,  PseudoColor, vi)) {
246 	/* VGA16 server. Argh. */
247     } else if (XMatchVisualInfo (display, screen, 1,  StaticGray,  vi)) {
248 	/* Mono server. Yuk */
249     } else {
250 	write_log ("Can't obtain appropriate X visual.\n");
251 	return 0;
252     }
253     return 1;
254 }
255 
get_visual_bit_unit(XVisualInfo * vi,int bitdepth)256 static int get_visual_bit_unit (XVisualInfo *vi, int bitdepth)
257 {
258     int bit_unit = 0;
259     XPixmapFormatValues *xpfvs;
260     int i,j;
261 
262     /* We now have the bitdepth of the display, but that doesn't tell us yet
263      * how many bits to use per pixel. The VGA16 server has a bitdepth of 4,
264      * but uses 1 byte per pixel. */
265     xpfvs = XListPixmapFormats (display, &i);
266     for (j = 0; j < i && xpfvs[j].depth != bitdepth; j++)
267 	;
268     if (j < i)
269 	bit_unit = xpfvs[j].bits_per_pixel;
270     XFree (xpfvs);
271     if (j == i) {
272 	write_log ("Your X server is feeling ill.\n");
273     }
274 
275     return bit_unit;
276 }
277 
278 #ifdef USE_VIDMODE_EXTENSION
279 static XF86VidModeModeInfo **allmodes;
280 static int vidmodecount;
281 
get_vidmodes(void)282 static int get_vidmodes (void)
283 {
284     return XF86VidModeGetAllModeLines (display, screen, &vidmodecount, &allmodes);
285 }
286 #endif
287 
288 #ifdef USE_DGA_EXTENSION
289 
290 static int fb_bank, fb_banks, fb_mem;
291 static char *fb_addr;
292 static int fb_width;
293 
switch_to_best_mode(void)294 static void switch_to_best_mode (void)
295 {
296     Screen *scr = ScreenOfDisplay (display, screen);
297     int w = WidthOfScreen (scr);
298     int h = HeightOfScreen (scr);
299     int d = DefaultDepthOfScreen (scr);
300 #ifdef USE_VIDMODE_EXTENSION
301     int i, best;
302     if (vidmodeavail) {
303 	best = 0;
304 	for (i = 1; i < vidmodecount; i++) {
305 	    if (allmodes[i]->hdisplay >= current_width
306 		&& allmodes[i]->vdisplay >= current_height
307 		&& allmodes[i]->hdisplay <= allmodes[best]->hdisplay
308 		&& allmodes[i]->vdisplay <= allmodes[best]->vdisplay)
309 		best = i;
310 	}
311 	write_log ("entering DGA mode: %dx%d (%d, %d)\n",
312 		allmodes[best]->hdisplay, allmodes[best]->vdisplay,
313 		current_width, current_height);
314 	XF86VidModeSwitchToMode (display, screen, allmodes[best]);
315 	XF86VidModeSetViewPort (display, screen, 0, 0);
316     }
317 #endif
318     XMoveWindow (display, mywin, 0, 0);
319     XWarpPointer (display, None, rootwin, 0, 0, 0, 0, 0, 0);
320     XF86DGADirectVideo (display, screen, XF86DGADirectGraphics | XF86DGADirectMouse | XF86DGADirectKeyb);
321     XF86DGASetViewPort (display, screen, 0, 0);
322     memset (fb_addr, 0, (w * h) * (d / 8));
323 }
324 
enter_dga_mode(void)325 static void enter_dga_mode (void)
326 {
327     XRaiseWindow (display, mywin);
328 
329     /* We want all the key presses */
330     XGrabKeyboard (display, rootwin, 1, GrabModeAsync,
331 		   GrabModeAsync,  CurrentTime);
332 
333     /* and all the mouse moves */
334     XGrabPointer (display, rootwin, 1, PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
335 		  GrabModeAsync, GrabModeAsync, None,  None, CurrentTime);
336 
337     switch_to_best_mode ();
338 
339     gfxvidinfo.rowbytes = fb_width*gfxvidinfo.pixbytes;
340     gfxvidinfo.bufmem = (unsigned char*)fb_addr;
341     gfxvidinfo.linemem = 0;
342     gfxvidinfo.emergmem = malloc (gfxvidinfo.rowbytes);
343     gfxvidinfo.maxblocklines = MAXBLOCKLINES_MAX;
344 }
345 
leave_dga_mode(void)346 static void leave_dga_mode (void)
347 {
348     XF86DGADirectVideo (display, screen, 0);
349     XUngrabPointer (display, CurrentTime);
350     XUngrabKeyboard (display, CurrentTime);
351 #ifdef USE_VIDMODE_EXTENSION
352     if (vidmodeavail)
353 	XF86VidModeSwitchToMode (display, screen, allmodes[0]);
354 #endif
355 }
356 #endif
357 
358 
359 /*
360  * Dummy buffer methods.
361  */
x11_lock(struct vidbuf_description * gfxinfo)362 static int x11_lock (struct vidbuf_description *gfxinfo)
363 {
364     return 1;
365 }
366 
x11_unlock(struct vidbuf_description * gfxinfo)367 static void x11_unlock (struct vidbuf_description *gfxinfo)
368 {
369 }
370 
371 /*
372  * Flush screen method
373  */
x11_flush_screen(struct vidbuf_description * gfxinfo,int first_line,int last_line)374 static void x11_flush_screen (struct vidbuf_description *gfxinfo, int first_line, int last_line)
375 {
376     XSync (display, 0);
377 }
378 
379 /*
380  * Template for flush_line() buffer method in low-bandwidth mode
381  *
382  * In low-bandwidth mode, we don't flush the complete line. For each line we try
383  * to find the smallest line segment that contains modified pixels and flush only
384  * that segment.
385  */
386 
387 #define x11_flush_line_lbw(gfxinfo, line_no, pixbytes, pixtype, mitshm)		\
388 										\
389     char    *src;								\
390     char    *dst;								\
391     int      xs   = 0;								\
392     int      xe   = gfxinfo->inwidth - 1;					\
393     int      len;								\
394     pixtype *newp = (pixtype *)gfxinfo->linemem;				\
395     pixtype *oldp = (pixtype *)((uae_u8 *)ami_dinfo.image_mem +			\
396 				line_no * ami_dinfo.ximg->bytes_per_line);	\
397 										\
398     /* Find first modified pixel on this line */				\
399     while (newp[xs] == oldp[xs]) {						\
400 	if (xs == xe)								\
401 	    return;								\
402 	xs++;									\
403     }										\
404 										\
405     /* Find last modified pixel */						\
406     while (newp[xe] == oldp[xe])						\
407 	xe--;									\
408 										\
409     dst = (char *)(oldp + xs);							\
410     src = (char *)(newp + xs);							\
411     len = xe - xs + 1;								\
412 										\
413     /* Copy changed pixels to buffer */						\
414     memcpy (dst, src, len * pixbytes);						\
415 										\
416     /* Blit changed pixels to the display */					\
417     if (!mitshm) {								\
418 	XPutImage (display, mywin, mygc,					\
419 		   ami_dinfo.ximg,						\
420 		   xs, line_no,							\
421 		   xs, line_no,							\
422 		   len,								\
423 		   1);								\
424     } else {									\
425 	XShmPutImage (display, mywin, mygc,					\
426 		      ami_dinfo.ximg,						\
427 		      xs, line_no,						\
428 		      xs, line_no,						\
429 		      len,							\
430 		      1,							\
431 		      0);							\
432     }
433 
434 /* Expand the above template for various bit depths and for with and without MITSHM */
435 
x11_flush_line_lbw_8bit(struct vidbuf_description * gfxinfo,int line_no)436 static void x11_flush_line_lbw_8bit         (struct vidbuf_description *gfxinfo, int line_no) { x11_flush_line_lbw (gfxinfo, line_no, 1, uae_u8,  0); }
x11_flush_line_lbw_16bit(struct vidbuf_description * gfxinfo,int line_no)437 static void x11_flush_line_lbw_16bit        (struct vidbuf_description *gfxinfo, int line_no) { x11_flush_line_lbw (gfxinfo, line_no, 2, uae_u16, 0); }
x11_flush_line_lbw_32bit(struct vidbuf_description * gfxinfo,int line_no)438 static void x11_flush_line_lbw_32bit        (struct vidbuf_description *gfxinfo, int line_no) { x11_flush_line_lbw (gfxinfo, line_no, 4, uae_u32, 0); }
x11_flush_line_lbw_8bit_mitshm(struct vidbuf_description * gfxinfo,int line_no)439 static void x11_flush_line_lbw_8bit_mitshm  (struct vidbuf_description *gfxinfo, int line_no) { x11_flush_line_lbw (gfxinfo, line_no, 1, uae_u8,  1); }
x11_flush_line_lbw_16bit_mitshm(struct vidbuf_description * gfxinfo,int line_no)440 static void x11_flush_line_lbw_16bit_mitshm (struct vidbuf_description *gfxinfo, int line_no) { x11_flush_line_lbw (gfxinfo, line_no, 2, uae_u16, 1); }
x11_flush_line_lbw_32bit_mitshm(struct vidbuf_description * gfxinfo,int line_no)441 static void x11_flush_line_lbw_32bit_mitshm (struct vidbuf_description *gfxinfo, int line_no) { x11_flush_line_lbw (gfxinfo, line_no, 4, uae_u32, 1); }
442 
443 /*
444  * flush_line() buffer method for dithered mode
445  */
x11_flush_line_dither(struct vidbuf_description * gfxinfo,int line_no)446 static void x11_flush_line_dither (struct vidbuf_description *gfxinfo, int line_no)
447 {
448     DitherLine ((uae_u8 *)ami_dinfo.image_mem + ami_dinfo.ximg->bytes_per_line * line_no,
449 		(uae_u16 *)gfxinfo->linemem, 0, line_no, gfxinfo->inwidth, bit_unit);
450 
451     DO_PUTIMAGE (ami_dinfo.ximg, 0, line_no, 0, line_no, gfxinfo->inwidth, 1);
452 }
453 
454 /*
455  * flush_line() buffer method for dithered mode using DGA
456  */
457 #ifdef USE_DGA_EXTENSION
x11_flush_line_dither_dga(struct vidbuf_description * gfxinfo,int line_no)458 static void x11_flush_line_dither_dga (struct vidbuf_description *gfxinfo, int line_no)
459 {
460     DitherLine ((unsigned char *)(fb_addr + fb_width * line_no),
461 		(uae_u16 *)gfxinfo->linemem, 0, line_no, gfxinfo->inwidth, bit_unit);
462 
463 }
464 #endif
465 
466 /*
467  * flush_block() buffer method for a normal image buffer (no dithering and not low-bandwidth)
468  */
x11_flush_block(struct vidbuf_description * gfxinfo,int first_line,int last_line)469 static void x11_flush_block (struct vidbuf_description *gfxinfo, int first_line, int last_line)
470 {
471     XPutImage (display, mywin, mygc,
472 	       ami_dinfo.ximg,
473 	       0, first_line,
474 	       0, first_line,
475 	       gfxinfo->inwidth,
476 	       last_line - first_line + 1);
477 }
478 
479 /*
480  * flush_block() buffer method for shm image buffer (no dithering and not low-bandwidth)
481  */
x11_flush_block_mitshm(struct vidbuf_description * gfxinfo,int first_line,int last_line)482 static void x11_flush_block_mitshm (struct vidbuf_description *gfxinfo, int first_line, int last_line)
483 {
484     XShmPutImage (display, mywin, mygc,
485 		  ami_dinfo.ximg,
486 		  0, first_line,
487 		  0, first_line,
488 		  gfxinfo->inwidth,
489 		  last_line - first_line + 1,
490 		  0);
491 }
492 
493 
bitsInMask(unsigned long mask)494 STATIC_INLINE int bitsInMask (unsigned long mask)
495 {
496     /* count bits in mask */
497     int n = 0;
498     while (mask) {
499 	n += mask & 1;
500 	mask >>= 1;
501     }
502     return n;
503 }
504 
maskShift(unsigned long mask)505 STATIC_INLINE int maskShift (unsigned long mask)
506 {
507     /* determine how far mask is shifted */
508     int n = 0;
509     while (!(mask & 1)) {
510 	n++;
511 	mask >>= 1;
512     }
513     return n;
514 }
515 
516 static unsigned long pixel_return[256];
517 static XColor parsed_xcolors[256];
518 static int ncolors = 0;
519 
520 static int blackval = 32767;
521 static int whiteval = 0;
522 
get_color(int r,int g,int b,xcolnr * cnp)523 static int get_color (int r, int g, int b, xcolnr *cnp)
524 {
525     XColor *col = parsed_xcolors + ncolors;
526     char str[10];
527 
528     sprintf (str, "rgb:%x/%x/%x", r, g, b);
529     XParseColor (display, cmap, str, col);
530     *cnp = col->pixel = pixel_return[ncolors];
531     XStoreColor (display, cmap, col);
532     XStoreColor (display, cmap2, col);
533 
534     if (r + g + b < blackval)
535 	blackval = r + g + b, black = *col;
536     if (r + g + b > whiteval)
537 	whiteval = r + g + b, white = *col;
538 
539     ncolors++;
540     return 1;
541 }
542 
init_colors(void)543 static int init_colors (void)
544 {
545     if (visualInfo.VI_CLASS == TrueColor) {
546 	red_bits = bitsInMask (visualInfo.red_mask);
547 	green_bits = bitsInMask (visualInfo.green_mask);
548 	blue_bits = bitsInMask (visualInfo.blue_mask);
549 	red_shift = maskShift (visualInfo.red_mask);
550 	green_shift = maskShift (visualInfo.green_mask);
551 	blue_shift = maskShift (visualInfo.blue_mask);
552     }
553 
554     if (need_dither) {
555 	if (bitdepth == 1)
556 	    setup_greydither (1, get_color);
557 	else
558 	    setup_dither (bitdepth, get_color);
559     } else {
560 	if (bitdepth != 8 && bitdepth != 12 && bitdepth != 15
561 	    && bitdepth != 16 && bitdepth != 24) {
562 	    write_log ("Unsupported bit depth (%d)\n", bitdepth);
563 	    return 0;
564 	}
565 
566 	switch (visualInfo.VI_CLASS) {
567 	 case TrueColor:
568 	    alloc_colors64k (red_bits, green_bits, blue_bits, red_shift,
569 			     green_shift, blue_shift, 0, 0, 0,
570 			     inverse_byte_order);
571 
572 	    XParseColor (display, cmap, "#000000", &black);
573 	    if (! XAllocColor (display, cmap, &black))
574 		write_log ("Whoops??\n");
575 	    XParseColor (display, cmap, "#ffffff", &white);
576 	    if (! XAllocColor (display, cmap, &white))
577 		write_log ("Whoops??\n");
578 	    break;
579 
580 	 case GrayScale:
581 	 case PseudoColor:
582 	    alloc_colors256 (get_color);
583 	    break;
584 
585 	 default:
586 	    write_log ("Unsupported visual class (%d)\n", visualInfo.VI_CLASS);
587 	    return 0;
588 	}
589     }
590     return 1;
591 }
592 
dga_available(void)593 static int dga_available (void)
594 {
595 #ifdef USE_DGA_EXTENSION
596     int MajorVersion, MinorVersion;
597     int EventBase, ErrorBase;
598 
599     if (! XF86DGAQueryVersion (display, &MajorVersion, &MinorVersion)) {
600 	write_log ("Unable to query video extension version\n");
601 	return 0;
602     }
603     if (! XF86DGAQueryExtension (display, &EventBase, &ErrorBase)) {
604 	write_log ("Unable to query video extension information\n");
605 	return 0;
606     }
607     /* Fail if the extension version in the server is too old */
608     if (MajorVersion < DGA_MINMAJOR
609 	|| (MajorVersion == DGA_MINMAJOR && MinorVersion < DGA_MINMINOR))
610     {
611 	write_log (
612 		 "Xserver is running an old XFree86-DGA version"
613 		 " (%d.%d)\n", MajorVersion, MinorVersion);
614 	write_log ("Minimum required version is %d.%d\n",
615 		 DGA_MINMAJOR, DGA_MINMINOR);
616 	return 0;
617     }
618     if (geteuid () != 0) {
619 	write_log ("UAE is not running as root, DGA extension disabled.\n");
620 	return 0;
621     }
622     if (! XF86DGAGetVideo (display, screen, &fb_addr, &fb_width, &fb_bank, &fb_mem)
623 	|| fb_bank < fb_mem)
624     {
625 	write_log ("Problems with DGA - disabling DGA extension.\n");
626 	return 0;
627     }
628     write_log ("DGA extension: addr:%X, width %d, bank size %d mem size %d\n",
629 	     fb_addr, fb_width, fb_bank, fb_mem);
630 
631     return 1;
632 #else
633     return 0;
634 #endif
635 }
636 
vid_mode_available(void)637 static int vid_mode_available (void)
638 {
639 #ifdef USE_VIDMODE_EXTENSION
640     int MajorVersion, MinorVersion;
641     int EventBase, ErrorBase;
642 
643     if (! dgaavail)
644 	return 0;
645     if (! XF86VidModeQueryVersion (display, &MajorVersion, &MinorVersion)) {
646 	write_log ("Unable to query video extension version\n");
647 	return 0;
648     }
649     if (! XF86VidModeQueryExtension (display, &EventBase, &ErrorBase)) {
650 	write_log ("Unable to query video extension information\n");
651 	return 0;
652     }
653     if (MajorVersion < VidMode_MINMAJOR
654 	|| (MajorVersion == VidMode_MINMAJOR && MinorVersion < VidMode_MINMINOR)) {
655 	/* Fail if the extension version in the server is too old */
656 	write_log ("Xserver is running an old XFree86-VidMode version (%d.%d)\n",
657 		 MajorVersion, MinorVersion);
658 	write_log ("Minimum required version is %d.%d\n",
659 		 VidMode_MINMAJOR, VidMode_MINMINOR);
660 	return 0;
661     }
662     if (! get_vidmodes ()) {
663 	write_log ("Error getting video mode information\n");
664 	return 0;
665     }
666     return 1;
667 #else
668     return 0;
669 #endif
670 }
671 
shm_available(void)672 static int shm_available (void)
673 {
674 #if SHM_SUPPORT_LINKS == 1
675     if (XShmQueryExtension (display))
676 	return 1;
677 #endif
678     return 0;
679 }
680 
graphics_setup(void)681 int graphics_setup (void)
682 {
683     char *display_name = 0;
684     const char *keycodes;
685 
686     display = XOpenDisplay (display_name);
687     if (display == 0)  {
688 	write_log ("Can't connect to X server %s\n", XDisplayName (display_name));
689 	return 0;
690     }
691 
692     shmavail = shm_available ();
693     dgaavail = dga_available ();
694     vidmodeavail = vid_mode_available ();
695 
696     {
697 	int local_byte_order;
698 	int x = 0x04030201;
699 	char *y=(char*)&x;
700 
701 	local_byte_order = y[0] == 0x04 ? MSBFirst : LSBFirst;
702 	if (ImageByteOrder(display) != local_byte_order)
703 	    inverse_byte_order = 1;
704     }
705 
706     screen  = XDefaultScreen (display);
707     rootwin = XRootWindow (display, screen);
708 
709     if (!get_best_visual (display, screen, &visualInfo))
710 	return 0;
711 
712     vis = visualInfo.visual;
713     bitdepth = visualInfo.depth;
714     if (!(bit_unit = get_visual_bit_unit (&visualInfo, bitdepth))) return 0;
715 
716     write_log ("X11GFX: Initialized.\n");
717 
718     rawkeys_available = 0;
719 
720 #if 0
721 #ifdef USE_XKB
722     keycodes = get_xkb_keycodes (display);
723 
724     if (keycodes) {
725 	/* We only support xfree86 keycodes for now */
726 	if (strncmp (keycodes, "xfree86", 7) == 0) {
727 	    rawkeys_available = 1;
728 	    raw_keyboard = uaekey_make_default_kbr (x11pc_keymap);
729 	    write_log ("X11GFX: Keyboard uses xfree86 keycodes\n");
730 	}
731     }
732 #endif
733 #endif
734 
735     return 1;
736 }
737 
lock_window_size(void)738 static void lock_window_size (void)
739 {
740     XSizeHints hint;
741 
742     hint.flags  = PMinSize | PMaxSize;
743     hint.min_width = current_width;
744     hint.min_height = current_height;
745     hint.max_width = current_width;
746     hint.max_height = current_height;
747     XSetWMNormalHints (display, mywin, &hint);
748 }
749 
init_dispinfo(struct disp_info * disp)750 static void init_dispinfo (struct disp_info *disp)
751 {
752 #if SHM_SUPPORT_LINKS == 1
753     disp->shminfo.shmid = -1;
754 #endif
755     disp->ximg = 0;
756 }
757 
graphics_subinit(void)758 static void graphics_subinit (void)
759 {
760     XSetWindowAttributes wattr;
761     XClassHint classhint;
762     XWMHints *hints;
763     unsigned long valuemask;
764 
765     dgamode = currprefs.gfx_apmode[screen_is_picasso ? APMODE_RTG : APMODE_NATIVE].gfx_fullscreen;
766 //    dgamode = screen_is_picasso ? currprefs.gfx_pfullscreen : currprefs.gfx_afullscreen;
767     dgamode = dgamode && dgaavail;
768 
769     wattr.background_pixel = /*black.pixel*/0;
770     wattr.backing_store = Always;
771     wattr.backing_planes = bitdepth;
772     wattr.border_pixmap = None;
773     wattr.border_pixel = /*black.pixel*/0;
774     wattr.colormap = cmap;
775     valuemask = (CWEventMask | CWBackPixel | CWBorderPixel
776 		 | CWBackingStore | CWBackingPlanes | CWColormap);
777 
778     if (dgamode) {
779 	wattr.event_mask = DGA_EVENTMASK;
780 	wattr.override_redirect = 1;
781 	valuemask |= CWOverrideRedirect;
782     } else
783 	wattr.event_mask = EVENTMASK;
784 
785     XSync (display, 0);
786 
787     delete_win = XInternAtom(display, "WM_DELETE_WINDOW", False);
788     mywin = XCreateWindow (display, rootwin, 0, 0, current_width, current_height,
789 			   0, bitdepth, InputOutput, vis, valuemask, &wattr);
790 	gfxvidinfo.width_allocated = current_width;
791 	gfxvidinfo.height_allocated = current_height;
792     XSetWMProtocols (display, mywin, &delete_win, 1);
793     XSync (display, 0);
794     XStoreName (display, mywin, PACKAGE_NAME);
795     XSetIconName (display, mywin, PACKAGE_NAME);
796 
797     /* set class hint */
798     classhint.res_name  = (char *)"UAE";
799     classhint.res_class = (char *)"UAEScreen";
800     XSetClassHint(display, mywin, &classhint);
801 
802     hints = XAllocWMHints();
803     /* Set window group leader to self to become an application
804      * that can be hidden by e.g. WindowMaker.
805      * Would be more useful if we could find out what the
806      * (optional) GTK+ window ID is :-/ */
807     hints->window_group = mywin;
808     hints->flags = WindowGroupHint;
809     XSetWMHints(display, mywin, hints);
810 
811     XMapRaised (display, mywin);
812     XSync (display, 0);
813     mygc = XCreateGC (display, mywin, 0, 0);
814 
815     if (dgamode) {
816 #ifdef USE_DGA_EXTENSION
817 	enter_dga_mode ();
818 	/*setuid(getuid());*/
819 	picasso_vidinfo.rowbytes = fb_width * picasso_vidinfo.pixbytes;
820 #endif
821     } else {
822 	get_image (current_width, current_height, &ami_dinfo);
823 	if (screen_is_picasso) {
824 	    get_image (current_width, current_height, &pic_dinfo);
825 	    picasso_vidinfo.rowbytes = pic_dinfo.ximg->bytes_per_line;
826 	}
827     }
828 
829     picasso_vidinfo.extra_mem = 1;
830 
831     gfxvidinfo.flush_screen = x11_flush_screen;
832     gfxvidinfo.lockscr      = x11_lock;
833     gfxvidinfo.unlockscr    = x11_unlock;
834 
835 
836     if (need_dither) {
837 	gfxvidinfo.maxblocklines = 0;
838 	gfxvidinfo.rowbytes = gfxvidinfo.pixbytes * currprefs.gfx_size_win.width;
839 	gfxvidinfo.linemem = malloc (gfxvidinfo.rowbytes);
840 	gfxvidinfo.flush_line  = x11_flush_line_dither;
841     } else if (! dgamode) {
842 	gfxvidinfo.emergmem = 0;
843 	gfxvidinfo.linemem = 0;
844 	gfxvidinfo.bufmem = (uae_u8 *)ami_dinfo.image_mem;
845 	gfxvidinfo.rowbytes = ami_dinfo.ximg->bytes_per_line;
846 	if (currprefs.x11_use_low_bandwidth) {
847 	    write_log ("Doing low-bandwidth output.\n");
848 	    gfxvidinfo.maxblocklines = 0;
849 	    gfxvidinfo.rowbytes = ami_dinfo.ximg->bytes_per_line;
850 	    gfxvidinfo.linemem = malloc (gfxvidinfo.rowbytes);
851 
852 	    if (shmavail && currprefs.x11_use_mitshm) {
853 		switch (gfxvidinfo.pixbytes) {
854 		    case 4  : gfxvidinfo.flush_line = x11_flush_line_lbw_32bit_mitshm; break;
855 		    case 2  : gfxvidinfo.flush_line = x11_flush_line_lbw_16bit_mitshm; break;
856 		    default : gfxvidinfo.flush_line = x11_flush_line_lbw_8bit_mitshm;  break;
857 		}
858 	    } else {
859 		switch (gfxvidinfo.pixbytes) {
860 		    case 4  : gfxvidinfo.flush_line = x11_flush_line_lbw_32bit; break;
861 		    case 2  : gfxvidinfo.flush_line = x11_flush_line_lbw_16bit; break;
862 		    default : gfxvidinfo.flush_line = x11_flush_line_lbw_8bit;	break;
863 		}
864 	    }
865 	} else {
866 	    gfxvidinfo.maxblocklines = MAXBLOCKLINES_MAX;
867 
868 	    if (shmavail && currprefs.x11_use_mitshm)
869 		gfxvidinfo.flush_block  = x11_flush_block_mitshm;
870 	    else
871 		gfxvidinfo.flush_block  = x11_flush_block;
872 	}
873     }
874 
875     if (visualInfo.VI_CLASS != TrueColor && ! screen_is_picasso) {
876 	int i;
877 	for (i = 0; i < 256; i++)
878 	    XStoreColor (display, cmap, parsed_xcolors + i);
879     }
880 
881 #ifdef USE_DGA_EXTENSION
882     if (dgamode) {
883 	dga_colormap_installed = 0;
884 	XF86DGAInstallColormap (display, screen, cmap2);
885 	XF86DGAInstallColormap (display, screen, cmap);
886     }
887 #endif
888 
889     if (! dgamode) {
890 	if (!currprefs.hide_cursor)
891 	    XDefineCursor (display, mywin, xhairCursor);
892 	else
893 	    XDefineCursor (display, mywin, blankCursor);
894 	cursorOn = 1;
895     }
896 
897     mousehack = !dgamode;
898 
899     if (screen_is_picasso) {
900 	picasso_has_invalid_lines = 0;
901 	picasso_invalid_start = picasso_vidinfo.height + 1;
902 	picasso_invalid_stop = -1;
903 	memset (picasso_invalid_lines, 0, sizeof picasso_invalid_lines);
904     } else
905 	reset_drawing ();
906 
907     inwindow = 0;
908     inputdevice_release_all_keys ();
909     reset_hotkeys ();
910 }
911 
graphics_init(void)912 int graphics_init (void)
913 {
914     if (currprefs.x11_use_mitshm && ! shmavail) {
915 	write_log ("MIT-SHM extension not supported by X server.\n");
916     }
917     if (currprefs.color_mode > 5)
918 	write_log ("Bad color mode selected. Using default.\n"), currprefs.color_mode = 0;
919 
920     x11_init_ok = 0;
921     need_dither = 0;
922     screen_is_picasso = 0;
923     dgamode = 0;
924 
925     init_dispinfo (&ami_dinfo);
926     init_dispinfo (&pic_dinfo);
927 
928     write_log ("Using %d bit visual, %d bits per pixel\n", bitdepth, bit_unit);
929 
930     fixup_prefs_dimensions (&currprefs);
931 
932     gfxvidinfo.inwidth = currprefs.gfx_size_win.width;
933     gfxvidinfo.inheight = currprefs.gfx_size_win.height;
934     current_width = currprefs.gfx_size_win.width;
935     current_height = currprefs.gfx_size_win.height;
936 
937     cmap = XCreateColormap (display, rootwin, vis, AllocNone);
938     cmap2 = XCreateColormap (display, rootwin, vis, AllocNone);
939     if (visualInfo.VI_CLASS == GrayScale || visualInfo.VI_CLASS == PseudoColor) {
940 	XAllocColorCells (display, cmap, 0, 0, 0, pixel_return, 1 << bitdepth);
941 	XAllocColorCells (display, cmap2, 0, 0, 0, pixel_return, 1 << bitdepth);
942     }
943 
944     if (bitdepth < 8 || (bitdepth == 8 && currprefs.color_mode == 3)) {
945 	gfxvidinfo.pixbytes = 2;
946 	currprefs.x11_use_low_bandwidth = 0;
947 	need_dither = 1;
948     } else {
949 	gfxvidinfo.pixbytes = bit_unit >> 3;
950     }
951 
952     if (! init_colors ())
953 	return 0;
954 
955     blankCursor = XCreatePixmapCursor (display,
956 				       XCreatePixmap (display, rootwin, 1, 1, 1),
957 				       XCreatePixmap (display, rootwin, 1, 1, 1),
958 				       &black, &white, 0, 0);
959     xhairCursor = XCreateFontCursor (display, XC_crosshair);
960 
961     graphics_subinit ();
962 
963     grabbed = 0;
964 
965     return x11_init_ok = 1;
966 }
967 
destroy_dinfo(struct disp_info * dinfo)968 static void destroy_dinfo (struct disp_info *dinfo)
969 {
970     if (dinfo->ximg == NULL)
971 	return;
972 #if SHM_SUPPORT_LINKS == 1
973     if (dinfo->shminfo.shmid != -1)
974 	shmdt (dinfo->shminfo.shmaddr);
975     dinfo->shminfo.shmid = -1;
976 #endif
977     XDestroyImage (dinfo->ximg);
978     dinfo->ximg = NULL;
979 }
980 
graphics_subshutdown(void)981 static void graphics_subshutdown (void)
982 {
983     XSync (display, 0);
984 #ifdef USE_DGA_EXTENSION
985     if (dgamode)
986 	leave_dga_mode ();
987 #endif
988 
989     destroy_dinfo (&ami_dinfo);
990     destroy_dinfo (&pic_dinfo);
991 
992     if (mywin) {
993 	XDestroyWindow (display, mywin);
994 	mywin = 0;
995     }
996 
997     xfree (gfxvidinfo.linemem);
998     xfree (gfxvidinfo.emergmem);
999 
1000     mousehack = 0;
1001 }
1002 
graphics_leave(void)1003 void graphics_leave (void)
1004 {
1005     if (! x11_init_ok)
1006 	return;
1007 
1008     graphics_subshutdown ();
1009 
1010     if (autorepeatoff)
1011 	XAutoRepeatOn (display);
1012 
1013     XFlush (display);
1014     XSync (display, 0);
1015 
1016     XFreeColormap (display, cmap);
1017     XFreeColormap (display, cmap2);
1018 
1019     XCloseDisplay (display);
1020 
1021     dumpcustom ();
1022 }
1023 
1024 static struct timeval lastMotionTime;
1025 
1026 static int refresh_necessary = 0;
1027 
graphics_notify_state(int state)1028 void graphics_notify_state (int state)
1029 {
1030 }
1031 
handle_events(void)1032 bool handle_events (void)
1033 {
1034     for (;;) {
1035 	XEvent event;
1036 #if 0
1037 	if (! XCheckMaskEvent (display, eventmask, &event))
1038 	    break;
1039 #endif
1040 	if (! XPending (display))
1041 	    break;
1042 
1043 	XNextEvent (display, &event);
1044 
1045 	switch (event.type) {
1046 	 case KeyPress:
1047 	 case KeyRelease: {
1048 	    int state = (event.type == KeyPress);
1049 
1050 #if 0 // map_raw_keys is marked "if 0" in options.h
1051 	    if (currprefs.map_raw_keys) {
1052 		unsigned int keycode = ((XKeyEvent *)&event)->keycode;
1053 		unsigned int ievent;
1054 
1055 		if ((ievent = match_hotkey_sequence (keycode, state)))
1056 		    handle_hotkey_event (ievent, state);
1057 		else
1058 		    inputdevice_translatekeycode (0, keycode, state);
1059 	    } else {
1060 #endif // 0
1061 		KeySym keysym;
1062 		int index = 0;
1063 		int ievent, amiga_keycode;
1064 		do {
1065 		    keysym = XLookupKeysym ((XKeyEvent *)&event, index);
1066 		    if ((ievent = match_hotkey_sequence (keysym, state))) {
1067 			handle_hotkey_event (ievent, state);
1068 			break;
1069 		    } else
1070 			if ((amiga_keycode = xkeysym2amiga (keysym)) >= 0) {
1071 			    inputdevice_do_keyboard (amiga_keycode, state);
1072 			    break;
1073 			}
1074 		    index++;
1075 		} while (keysym != NoSymbol);
1076 #if 0 // from removal above
1077 	    }
1078 #endif // 0
1079 	    break;
1080 	 }
1081 	 case ButtonPress:
1082 	 case ButtonRelease: {
1083 	    int state = (event.type == ButtonPress);
1084 	    int buttonno = -1;
1085 	    switch ((int)((XButtonEvent *)&event)->button) {
1086 		case 1:  buttonno = 0; break;
1087 		case 2:  buttonno = 2; break;
1088 		case 3:  buttonno = 1; break;
1089 		/* buttons 4 and 5 report mousewheel events */
1090 		case 4:  if (state) record_key (0x7a << 1); break;
1091 		case 5:  if (state) record_key (0x7b << 1); break;
1092 	    }
1093 	    if (buttonno >=0)
1094 		setmousebuttonstate(0, buttonno, state);
1095 	    break;
1096 	 }
1097 	 case MotionNotify:
1098 	    if (dgamode) {
1099 		int tx = ((XMotionEvent *)&event)->x_root;
1100 		int ty = ((XMotionEvent *)&event)->y_root;
1101 		setmousestate (0, 0, tx, 0);
1102 		setmousestate (0, 1, ty, 0);
1103 	    } else if (grabbed) {
1104 		int realmove = 0;
1105 		int tx, ty,ttx,tty;
1106 
1107 		tx = ((XMotionEvent *)&event)->x;
1108 		ty = ((XMotionEvent *)&event)->y;
1109 
1110 		if (! event.xmotion.send_event) {
1111 		    setmousestate( 0,0,tx-oldx,0);
1112 		    setmousestate( 0,1,ty-oldy,0);
1113 		    realmove = 1;
1114 #undef ABS
1115 #define ABS(a) (((a)<0) ? -(a) : (a) )
1116 		    if (ABS(current_width / 2 - tx) > 3 * current_width / 8
1117 			|| ABS(current_height / 2 - ty) > 3 * current_height / 8)
1118 		    {
1119 #undef ABS
1120 			XEvent event;
1121 			ttx = current_width / 2;
1122 			tty = current_height / 2;
1123 			event.type = MotionNotify;
1124 			event.xmotion.display = display;
1125 			event.xmotion.window = mywin;
1126 			event.xmotion.x = ttx;
1127 			event.xmotion.y = tty;
1128 			XSendEvent (display, mywin, False,
1129 				    PointerMotionMask, &event);
1130 			XWarpPointer (display, None, mywin, 0, 0, 0, 0, ttx, tty);
1131 		    }
1132 		} else {
1133 		    tx=event.xmotion.x;
1134 		    ty=event.xmotion.y;
1135 		}
1136 		oldx = tx;
1137 		oldy = ty;
1138 	    } else if (inwindow) {
1139 		int tx = ((XMotionEvent *)&event)->x;
1140 		int ty = ((XMotionEvent *)&event)->y;
1141 		setmousestate(0,0,tx,1);
1142 		setmousestate(0,1,ty,1);
1143 		if (! cursorOn && !currprefs.hide_cursor) {
1144 		    XDefineCursor(display, mywin, xhairCursor);
1145 		    cursorOn = 1;
1146 		}
1147 		gettimeofday(&lastMotionTime, NULL);
1148 	    }
1149 	    break;
1150 	 case EnterNotify:
1151 	    {
1152 		int tx = ((XCrossingEvent *)&event)->x;
1153 		int ty = ((XCrossingEvent *)&event)->y;
1154 		setmousestate(0,0,tx,1);
1155 		setmousestate(0,1,ty,1);
1156 	    }
1157 	    inwindow = 1;
1158 	    break;
1159 	 case LeaveNotify:
1160 	    inwindow = 0;
1161 	    break;
1162 	 case FocusIn:
1163 	    if (! autorepeatoff)
1164 		XAutoRepeatOff (display);
1165 	    autorepeatoff = 1;
1166 	    break;
1167 	 case FocusOut:
1168 	    if (autorepeatoff)
1169 		XAutoRepeatOn (display);
1170 	    autorepeatoff = 0;
1171 	    inputdevice_release_all_keys ();
1172 	    break;
1173 	 case Expose:
1174 	    refresh_necessary = 1;
1175 	    break;
1176 	 case ClientMessage:
1177 	    if (((Atom)event.xclient.data.l[0]) == delete_win) {
1178 		//uae_stop ();
1179 	    }
1180 	    break;
1181 	}
1182     }
1183 
1184 #if defined PICASSO96
1185     if (! dgamode) {
1186 	if (screen_is_picasso && refresh_necessary) {
1187 	    DO_PUTIMAGE (pic_dinfo.ximg, 0, 0, 0, 0,
1188 			 picasso_vidinfo.width, picasso_vidinfo.height);
1189 	    XFlush (display);
1190 	    refresh_necessary = 0;
1191 	    memset (picasso_invalid_lines, 0, sizeof picasso_invalid_lines);
1192 	} else if (screen_is_picasso && picasso_has_invalid_lines) {
1193 	    int i;
1194 	    int strt = -1;
1195 
1196 	    picasso_invalid_lines[picasso_vidinfo.height] = 0;
1197 	    for (i = picasso_invalid_start; i < picasso_invalid_stop + 2; i++) {
1198 		if (picasso_invalid_lines[i]) {
1199 		    picasso_invalid_lines[i] = 0;
1200 		    if (strt != -1)
1201 			continue;
1202 		    strt = i;
1203 		} else {
1204 		    if (strt == -1)
1205 			continue;
1206 		    DO_PUTIMAGE (pic_dinfo.ximg, 0, strt, 0, strt,
1207 				 picasso_vidinfo.width, i - strt);
1208 		    strt = -1;
1209 		}
1210 	    }
1211 	    XFlush (display);
1212 	    if (strt != -1)
1213 		abort ();
1214 	}
1215     }
1216     picasso_has_invalid_lines = 0;
1217     picasso_invalid_start = picasso_vidinfo.height + 1;
1218     picasso_invalid_stop = -1;
1219 #endif
1220 
1221     if (! dgamode) {
1222 	if (! screen_is_picasso && refresh_necessary) {
1223 	    DO_PUTIMAGE (ami_dinfo.ximg, 0, 0, 0, 0, current_width, current_height);
1224 	    refresh_necessary = 0;
1225 	}
1226 	if (cursorOn && !currprefs.hide_cursor) {
1227 	    struct timeval now;
1228 	    int diff;
1229 	    gettimeofday(&now, NULL);
1230 	    diff = (now.tv_sec - lastMotionTime.tv_sec) * 1000000 +
1231 		(now.tv_usec - lastMotionTime.tv_usec);
1232 	    if (diff > 1000000) {
1233 		XDefineCursor (display, mywin, blankCursor);
1234 		cursorOn = 0;
1235 	    }
1236 	}
1237     }
1238 	return pause_emulation != 0;
1239 }
1240 
check_prefs_changed_gfx(void)1241 int check_prefs_changed_gfx (void)
1242 {
1243     if (changed_prefs.gfx_size_win.width != currprefs.gfx_size_win.width
1244 	|| changed_prefs.gfx_size_win.height != currprefs.gfx_size_win.height)
1245 	fixup_prefs_dimensions (&changed_prefs);
1246 
1247     if (changed_prefs.gfx_size_win.width == currprefs.gfx_size_win.width
1248 	&& changed_prefs.gfx_size_win.height == currprefs.gfx_size_win.height
1249 	&& changed_prefs.gfx_vresolution == currprefs.gfx_vresolution
1250 	&& changed_prefs.gfx_xcenter == currprefs.gfx_xcenter
1251 	&& changed_prefs.gfx_ycenter == currprefs.gfx_ycenter
1252 	&& changed_prefs.gfx_apmode[APMODE_RTG].gfx_fullscreen == currprefs.gfx_apmode[APMODE_RTG].gfx_fullscreen
1253 	&& changed_prefs.gfx_apmode[APMODE_NATIVE].gfx_fullscreen == currprefs.gfx_apmode[APMODE_NATIVE].gfx_fullscreen)
1254 	return 0;
1255 
1256     graphics_subshutdown ();
1257     currprefs.gfx_size_win.width = changed_prefs.gfx_size_win.width;
1258     currprefs.gfx_size_win.height = changed_prefs.gfx_size_win.height;
1259     currprefs.gfx_vresolution = changed_prefs.gfx_vresolution;
1260     currprefs.gfx_xcenter = changed_prefs.gfx_xcenter;
1261     currprefs.gfx_ycenter = changed_prefs.gfx_ycenter;
1262     currprefs.gfx_apmode[APMODE_NATIVE].gfx_fullscreen = changed_prefs.gfx_apmode[APMODE_NATIVE].gfx_fullscreen;
1263     currprefs.gfx_apmode[APMODE_RTG].gfx_fullscreen = changed_prefs.gfx_apmode[APMODE_RTG].gfx_fullscreen;
1264 
1265     graphics_subinit ();
1266 
1267     if (! inwindow)
1268 	XWarpPointer (display, None, mywin, 0, 0, 0, 0,
1269 		      current_width / 2, current_height / 2);
1270 
1271     notice_screen_contents_lost ();
1272     init_row_map ();
1273     if (screen_is_picasso)
1274 	picasso_enablescreen (1);
1275     return 0;
1276 }
1277 
debuggable(void)1278 int debuggable (void)
1279 {
1280     return 1;
1281 }
1282 
mousehack_allowed(void)1283 int mousehack_allowed (void)
1284 {
1285     return mousehack;
1286 }
1287 
1288 #ifdef PICASSO96
1289 
DX_Invalidate(int first,int last)1290 void DX_Invalidate (int first, int last)
1291 {
1292     if (first > last)
1293 	return;
1294 
1295     picasso_has_invalid_lines = 1;
1296     if (first < picasso_invalid_start)
1297 	picasso_invalid_start = first;
1298     if (last > picasso_invalid_stop)
1299 	picasso_invalid_stop = last;
1300 
1301     while (first <= last) {
1302 	picasso_invalid_lines[first] = 1;
1303 	first++;
1304     }
1305 }
1306 
1307 static int palette_update_start=256;
1308 static int palette_update_end=0;
1309 
DX_SetPalette_real(int start,int count)1310 static void DX_SetPalette_real (int start, int count)
1311 {
1312     if (! screen_is_picasso || picasso96_state.RGBFormat != RGBFB_CHUNKY)
1313 	return;
1314 
1315     if (picasso_vidinfo.pixbytes != 1) {
1316 	/* This is the case when we're emulating a 256 color display.  */
1317 	while (count-- > 0) {
1318 	    int r = picasso96_state.CLUT[start].Red;
1319 	    int g = picasso96_state.CLUT[start].Green;
1320 	    int b = picasso96_state.CLUT[start].Blue;
1321 	    picasso_vidinfo.clut[start++] = (doMask256 (r, red_bits, red_shift)
1322 					     | doMask256 (g, green_bits, green_shift)
1323 					     | doMask256 (b, blue_bits, blue_shift));
1324 	}
1325 	return;
1326     }
1327 
1328     while (count-- > 0) {
1329 	XColor col = parsed_xcolors[start];
1330 	col.red = picasso96_state.CLUT[start].Red * 0x0101;
1331 	col.green = picasso96_state.CLUT[start].Green * 0x0101;
1332 	col.blue = picasso96_state.CLUT[start].Blue * 0x0101;
1333 	XStoreColor (display, cmap, &col);
1334 	XStoreColor (display, cmap2, &col);
1335 	start++;
1336     }
1337 #ifdef USE_DGA_EXTENSION
1338     if (dgamode) {
1339 	dga_colormap_installed ^= 1;
1340 	if (dga_colormap_installed == 1)
1341 	    XF86DGAInstallColormap (display, screen, cmap2);
1342 	else
1343 	    XF86DGAInstallColormap (display, screen, cmap);
1344     }
1345 #endif
1346 }
DX_SetPalette(int start,int count)1347 void DX_SetPalette (int start, int count)
1348 {
1349    DX_SetPalette_real (start, count);
1350 }
1351 
DX_SetPalette_delayed(int start,int count)1352 static void DX_SetPalette_delayed (int start, int count)
1353 {
1354     if (bit_unit!=8) {
1355 	DX_SetPalette_real(start,count);
1356 	return;
1357     }
1358     if (start<palette_update_start)
1359 	palette_update_start=start;
1360     if (start+count>palette_update_end)
1361 	palette_update_end=start+count;
1362 }
1363 
DX_SetPalette_vsync(void)1364 void DX_SetPalette_vsync(void)
1365 {
1366   if (palette_update_end>palette_update_start) {
1367     DX_SetPalette_real(palette_update_start,
1368 		       palette_update_end-palette_update_start);
1369     palette_update_end=0;
1370     palette_update_start=256;
1371   }
1372 }
1373 
DX_Fill(int dstx,int dsty,int width,int height,uae_u32 color,RGBFTYPE rgbtype)1374 int DX_Fill (int dstx, int dsty, int width, int height, uae_u32 color, RGBFTYPE rgbtype)
1375 {
1376     /* not implemented yet */
1377     return 0;
1378 }
1379 
DX_Blit(int srcx,int srcy,int dstx,int dsty,int width,int height,BLIT_OPCODE opcode)1380 int DX_Blit (int srcx, int srcy, int dstx, int dsty, int width, int height, BLIT_OPCODE opcode)
1381 {
1382     /* not implemented yet */
1383     return 0;
1384 }
1385 
1386 #define MAX_SCREEN_MODES 12
1387 
1388 static int x_size_table[MAX_SCREEN_MODES] = { 320, 320, 320, 320, 640, 640, 640, 800, 1024, 1152, 1280, 1280 };
1389 static int y_size_table[MAX_SCREEN_MODES] = { 200, 240, 256, 400, 350, 480, 512, 600, 768,  864,  960,  1024 };
1390 
set_window_for_picasso(void)1391 static void set_window_for_picasso (void)
1392 {
1393     if (current_width == picasso_vidinfo.width && current_height == picasso_vidinfo.height)
1394 	return;
1395 
1396     current_width = picasso_vidinfo.width;
1397     current_height = picasso_vidinfo.height;
1398     XResizeWindow (display, mywin, current_width, current_height);
1399 #if defined USE_DGA_EXTENSION && defined USE_VIDMODE_EXTENSION
1400     if (dgamode && vidmodeavail)
1401 	switch_to_best_mode ();
1402 #endif
1403 }
1404 
gfx_set_picasso_modeinfo(uae_u32 w,uae_u32 h,uae_u32 depth,RGBFTYPE rgbfmt)1405 void gfx_set_picasso_modeinfo (uae_u32 w, uae_u32 h, uae_u32 depth, RGBFTYPE rgbfmt)
1406 {
1407     picasso_vidinfo.width = w;
1408     picasso_vidinfo.height = h;
1409     picasso_vidinfo.depth = depth;
1410     picasso_vidinfo.pixbytes = bit_unit >> 3;
1411 
1412     if (screen_is_picasso)
1413 	set_window_for_picasso ();
1414 }
1415 
gfx_set_picasso_state(int on)1416 void gfx_set_picasso_state (int on)
1417 {
1418     if (on == screen_is_picasso)
1419 	return;
1420 
1421     /* We can get called by drawing_init() when there's
1422      * no window opened yet... */
1423     if (mywin == 0)
1424 	return;
1425 
1426     write_log ("set_picasso_state:%d\n", on);
1427     graphics_subshutdown ();
1428     screen_is_picasso = on;
1429     if (on) {
1430 	current_width = picasso_vidinfo.width;
1431 	current_height = picasso_vidinfo.height;
1432 	graphics_subinit ();
1433     } else {
1434 	current_width = gfxvidinfo.outwidth;
1435 	current_height = gfxvidinfo.outheight;
1436 	graphics_subinit ();
1437 	reset_drawing ();
1438     }
1439     if (on)
1440 	DX_SetPalette_real (0, 256);
1441 }
1442 
gfx_lock_picasso(bool fullupdate,bool doclear)1443 uae_u8 *gfx_lock_picasso (bool fullupdate, bool doclear)
1444 {
1445 #ifdef USE_DGA_EXTENSION
1446     if (dgamode)
1447 		return (uae_u8 *)fb_addr;
1448     else
1449 #endif
1450 	return (uae_u8 *)pic_dinfo.ximg->data;
1451 }
1452 
gfx_unlock_picasso(bool dorender)1453 void gfx_unlock_picasso (bool dorender)
1454 {
1455 }
1456 #endif
1457 
toggle_mousegrab(void)1458 void toggle_mousegrab (void)
1459 {
1460     if (grabbed) {
1461 	XUngrabPointer (display, CurrentTime);
1462 //	XUndefineCursor (display, mywin);
1463 	grabbed = 0;
1464 	mousehack = 1;
1465 	write_log ("Ungrabbed mouse\n");
1466     } else if (! dgamode) {
1467 	XGrabPointer (display, mywin, 1, 0, GrabModeAsync, GrabModeAsync,
1468 		      mywin, blankCursor, CurrentTime);
1469 	oldx = current_width / 2;
1470 	oldy = current_height / 2;
1471 	XWarpPointer (display, None, mywin, 0, 0, 0, 0, oldx, oldy);
1472 	write_log ("Grabbed mouse\n");
1473 	grabbed = 1;
1474 	mousehack = 0;
1475     }
1476 }
1477 
is_fullscreen(void)1478 int is_fullscreen (void)
1479 {
1480 #ifdef USE_DGA_EXTENSION
1481     return dgamode;
1482 #else
1483     return 0;
1484 #endif
1485 }
1486 
is_vsync(void)1487 int is_vsync (void)
1488 {
1489     return 0;
1490 }
1491 
toggle_fullscreen(int mode)1492 void toggle_fullscreen (int mode)
1493 {
1494 #ifdef USE_DGA_EXTENSION
1495     changed_prefs.gfx_apmode[APMODE_NATIVE].gfx_fullscreen
1496 		= changed_prefs.gfx_apmode[APMODE_RTG].gfx_fullscreen
1497 		= !dgamode;
1498 #endif
1499 }
1500 
screenshot(int mode,int doprepare)1501 void screenshot (int mode, int doprepare)
1502 {
1503     write_log ("Screenshot not implemented yet\n");
1504 }
1505 
1506 /*
1507  * Mouse inputdevice functions
1508  */
1509 
1510 /* Hardwire for 3 axes and 3 buttons
1511  * There is no 3rd axis as such - mousewheel events are
1512  * supplied by X on buttons 4 and 5.
1513  */
1514 #define MAX_BUTTONS     3
1515 #define MAX_AXES        3
1516 #define FIRST_AXIS      0
1517 #define FIRST_BUTTON    MAX_AXES
1518 
init_mouse(void)1519 static int init_mouse (void)
1520 {
1521    return 1;
1522 }
1523 
close_mouse(void)1524 static void close_mouse (void)
1525 {
1526    return;
1527 }
1528 
acquire_mouse(int num,int flags)1529 static int acquire_mouse (int num, int flags)
1530 {
1531    return 1;
1532 }
1533 
unacquire_mouse(int num)1534 static void unacquire_mouse (int num)
1535 {
1536    return;
1537 }
1538 
get_mouse_num(void)1539 static int get_mouse_num (void)
1540 {
1541     return 1;
1542 }
1543 
get_mouse_friendlyname(int mouse)1544 static TCHAR *get_mouse_friendlyname (int mouse)
1545 {
1546     return "Default mouse";
1547 }
1548 
get_mouse_uniquename(int mouse)1549 static TCHAR *get_mouse_uniquename (int mouse)
1550 {
1551 	return "DEFMOUSE1";
1552 }
1553 
get_mouse_widget_num(int mouse)1554 static int get_mouse_widget_num (int mouse)
1555 {
1556     return MAX_AXES + MAX_BUTTONS;
1557 }
1558 
get_mouse_widget_first(int mouse,int type)1559 static int get_mouse_widget_first (int mouse, int type)
1560 {
1561     switch (type) {
1562 	case IDEV_WIDGET_BUTTON:
1563 	    return FIRST_BUTTON;
1564 	case IDEV_WIDGET_AXIS:
1565 	    return FIRST_AXIS;
1566     }
1567     return -1;
1568 }
1569 
get_mouse_widget_type(int mouse,int num,TCHAR * name,uae_u32 * code)1570 static int get_mouse_widget_type (int mouse, int num, TCHAR *name, uae_u32 *code)
1571 {
1572     if (num >= MAX_AXES && num < MAX_AXES + MAX_BUTTONS) {
1573 	if (name)
1574 	    sprintf (name, "Button %d", num + 1 + MAX_AXES);
1575 	return IDEV_WIDGET_BUTTON;
1576     } else if (num < MAX_AXES) {
1577 	if (name)
1578 	    sprintf (name, "Axis %d", num + 1);
1579 	return IDEV_WIDGET_AXIS;
1580     }
1581     return IDEV_WIDGET_NONE;
1582 }
1583 
read_mouse(void)1584 static void read_mouse (void)
1585 {
1586     /* We handle mouse input in handle_events() */
1587 }
1588 
get_mouse_flags(int num)1589 static int get_mouse_flags (int num)
1590 {
1591         return 0;
1592 }
1593 
1594 struct inputdevice_functions inputdevicefunc_mouse = {
1595     init_mouse,
1596     close_mouse,
1597     acquire_mouse,
1598     unacquire_mouse,
1599     read_mouse,
1600     get_mouse_num,
1601     get_mouse_friendlyname,
1602     get_mouse_uniquename,
1603     get_mouse_widget_num,
1604     get_mouse_widget_type,
1605     get_mouse_widget_first,
1606     get_mouse_flags
1607 };
1608 
1609 /*
1610  * Keyboard inputdevice functions
1611  */
get_kb_num(void)1612 static int get_kb_num (void)
1613 {
1614     return 1;
1615 }
1616 
get_kb_friendlyname(int kb)1617 static TCHAR *get_kb_friendlyname (int kb)
1618 {
1619     return "Default keyboard";
1620 }
1621 
get_kb_uniquename(int kb)1622 static TCHAR *get_kb_uniquename (int kb)
1623 {
1624     return "DEFKEYB1";
1625 }
1626 
get_kb_widget_num(int kb)1627 static int get_kb_widget_num (int kb)
1628 {
1629     return 255; // fix me
1630 }
1631 
get_kb_widget_first(int kb,int type)1632 static int get_kb_widget_first ( int kb, int type)
1633 {
1634     return 0;
1635 }
1636 
get_kb_widget_type(int kb,int num,TCHAR * name,uae_u32 * code)1637 static int get_kb_widget_type (int kb, int num, TCHAR *name, uae_u32 *code)
1638 {
1639     // fix me
1640     if(code) *code = num;
1641     return IDEV_WIDGET_KEY;
1642 }
1643 
keyhack(int scancode,int pressed,int num)1644 static int keyhack (int scancode, int pressed, int num)
1645 {
1646     return scancode;
1647 }
1648 
read_kb(void)1649 static void read_kb (void)
1650 {
1651 }
1652 
init_kb(void)1653 static int init_kb (void)
1654 {
1655 #if 0 // map_raw_keys marked "if 0" in options.h
1656     if (currprefs.map_raw_keys) {
1657 	if (rawkeys_available) {
1658 //	    inputdevice_setkeytranslation (raw_keyboard, kbmaps);
1659 	    set_default_hotkeys (x11pc_hotkeys);
1660 	    write_log ("X11GFX: Enabling raw key-mapping.\n");
1661 	} else {
1662 	    currprefs.map_raw_keys = 0;
1663 	    write_log ("X11GFX: Raw key-mapping disabled. Keycodes not supported.\n");
1664 	}
1665     } else
1666 #endif // 0
1667 	write_log ("X11GFX: Raw key-mapping disabled.\n");
1668 
1669 #if 0 // map_raw_keys marked "if 0" in options.h
1670     if (!currprefs.map_raw_keys)
1671 	set_default_hotkeys (get_x11_default_hotkeys ());
1672 #endif // 0
1673 
1674     return 1;
1675 }
1676 
close_kb(void)1677 static void close_kb (void)
1678 {
1679 }
1680 
acquire_kb(int num,int flags)1681 static int acquire_kb (int num, int flags)
1682 {
1683     return 1;
1684 }
1685 
unacquire_kb(int num)1686 static void unacquire_kb (int num)
1687 {
1688 }
1689 
1690 /*
1691  * Default inputdevice config for X11 mouse
1692  */
input_get_default_mouse(struct uae_input_device * uid,int num,int port,int af,bool gp,bool wheel)1693 int input_get_default_mouse (struct uae_input_device *uid, int num, int port, int af, bool gp, bool wheel)
1694 {
1695     /* Supports only one mouse */
1696     uid[0].eventid[ID_AXIS_OFFSET + 0][0]   = INPUTEVENT_MOUSE1_HORIZ;
1697     uid[0].eventid[ID_AXIS_OFFSET + 1][0]   = INPUTEVENT_MOUSE1_VERT;
1698     uid[0].eventid[ID_AXIS_OFFSET + 2][0]   = INPUTEVENT_MOUSE1_WHEEL;
1699     uid[0].eventid[ID_BUTTON_OFFSET + 0][0] = INPUTEVENT_JOY1_FIRE_BUTTON;
1700     uid[0].eventid[ID_BUTTON_OFFSET + 1][0] = INPUTEVENT_JOY1_2ND_BUTTON;
1701     uid[0].eventid[ID_BUTTON_OFFSET + 2][0] = INPUTEVENT_JOY1_3RD_BUTTON;
1702     uid[0].enabled = 1;
1703 	return 0;
1704 }
1705 
get_kb_flags(int num)1706 static int get_kb_flags (int num)
1707 {
1708 	return 0;
1709 }
1710 
1711 struct inputdevice_functions inputdevicefunc_keyboard =
1712 {
1713     init_kb,
1714     close_kb,
1715     acquire_kb,
1716     unacquire_kb,
1717     read_kb,
1718     get_kb_num,
1719     get_kb_friendlyname,
1720     get_kb_uniquename,
1721     get_kb_widget_num,
1722     get_kb_widget_type,
1723     get_kb_widget_first,
1724 	get_kb_flags
1725 };
1726 
getcapslockstate(void)1727 int getcapslockstate (void)
1728 {
1729     return 0;
1730 }
1731 
setcapslockstate(int state)1732 void setcapslockstate (int state)
1733 {
1734 }
1735 
target_checkcapslock(int scancode,int * state)1736 int target_checkcapslock (int scancode, int *state)
1737 {
1738         if (scancode != DIK_CAPITAL && scancode != DIK_NUMLOCK && scancode != DIK_SCROLL)
1739                 return 0;
1740         if (*state == 0)
1741                 return -1;
1742 
1743         /*
1744         if (scancode == DIK_CAPITAL)
1745                 *state = SDL_GetModState() & KMOD_CAPS;
1746         if (scancode == DIK_NUMLOCK)
1747                 *state = SDL_GetModState() & KMOD_NUM;
1748         if (scancode == DIK_SCROLL)
1749                 *state = host_scrolllockstate;
1750         return 1;
1751         */
1752         return 0;
1753 }
1754 
1755 /*
1756  * Handle gfx cfgfile options
1757  */
gfx_save_options(FILE * f,const struct uae_prefs * p)1758 void gfx_save_options (FILE *f, const struct uae_prefs *p)
1759 {
1760     fprintf (f, "x11.low_bandwidth=%s\n", p->x11_use_low_bandwidth ? "true" : "false");
1761     fprintf (f, "x11.use_mitshm=%s\n",    p->x11_use_mitshm ? "true" : "false");
1762 #if 0 // map_raw_keys marked "if 0" in options.h
1763     fprintf (f, "x11.map_raw_keys=%s\n",  p->map_raw_keys ? "true" : "false");
1764 #endif // 0
1765 }
1766 
gfx_parse_option(struct uae_prefs * p,const char * option,const char * value)1767 int gfx_parse_option (struct uae_prefs *p, const char *option, const char *value)
1768 {
1769     return (cfgfile_yesno (option, value, "low_bandwidth", &p->x11_use_low_bandwidth)
1770 	 || cfgfile_yesno (option, value, "use_mitshm",    &p->x11_use_mitshm)
1771 	 || cfgfile_yesno (option, value, "hide_cursor",   &p->hide_cursor) /* Compatibility. This was an X11-specific option. */
1772 #if 0 // map_raw_keys marked "if 0" in options.h
1773 	 || cfgfile_yesno (option, value, "map_raw_keys",  &p->map_raw_keys));
1774 #endif // 0
1775 	);
1776 }
1777 
gfx_default_options(struct uae_prefs * p)1778 void gfx_default_options (struct uae_prefs *p)
1779 {
1780     p->x11_use_low_bandwidth = 0;
1781     p->x11_use_mitshm        = 1;
1782 #if 0 // map_raw_keys marked "if 0" in options.h
1783     p->map_raw_keys          = rawkeys_available;
1784 #endif // 0
1785 }
1786 
setmaintitle(void)1787 void setmaintitle (void)
1788 {
1789 	/* not implemented yet */
1790 }
1791 
1792 #if defined PICASSO96
picasso_palette(void)1793 int picasso_palette (void)
1794 {
1795 	int i = 0, changed = 0;
1796 
1797 	for ( ; i < 256; i++) {
1798 		int r = picasso96_state.CLUT[i].Red;
1799 		int g = picasso96_state.CLUT[i].Green;
1800 		int b = picasso96_state.CLUT[i].Blue;
1801 		uae_u32 v = (doMask256 (r, red_bits, red_shift)
1802 				| doMask256 (g, green_bits, green_shift)
1803 				| doMask256 (b, blue_bits, blue_shift));
1804 		if (v !=  picasso_vidinfo.clut[i]) {
1805 			picasso_vidinfo.clut[i] = v;
1806 			changed = 1;
1807 		}
1808 	}
1809 	return changed;
1810 }
1811 
gfx_set_picasso_colors(RGBFTYPE rgbfmt)1812 void gfx_set_picasso_colors (RGBFTYPE rgbfmt)
1813 {
1814 	alloc_colors_picasso (red_bits, green_bits, blue_bits, red_shift, green_shift, blue_shift, rgbfmt);
1815 }
1816 #endif // defined
1817