1 /* term_x11.c: X-windows terminal code (screen update and keyboard)
2 
3    Copyright (c) 1997-2003, Tarik Isani (xhomer@isani.org)
4 
5    This file is part of Xhomer.
6 
7    Xhomer is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License version 2
9    as published by the Free Software Foundation.
10 
11    Xhomer is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15 
16    You should have received a copy of the GNU General Public License
17    along with Xhomer; if not, write to the Free Software
18    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 */
20 
21 
22 /* TBD:
23 		-alloc only 2 colors for non-ebo 8-bit
24 		-use better technique to detect CLUT modes
25 		-add DGA mode that only writes each pixel once
26 		-colormap is not loaded for DGA+PCM
27 		-get screensaver blanking to work during DGA switch
28 
29    Xserver DGA2 bugs:
30 
31    Currently, standard X event handling is used, as the DGA stuff is broken
32    in DGA2
33 
34      XFree 4.0.2 Neomagic
35        -Use of more than 4MB of graphics memory causes crash during modeswitch
36        -Menu does not work if more than X MB of graphics memory is used
37        -XDGA events are not being seen (see #ifdef DGAXXX)
38        -XDGAFlipImmediate is not supported.  So, xhomer will wait until the
39         viewport update has been completed, causing slower scrolling with
40         this server.  Servers that support XDGAFlipImmediate are not
41         affected.
42 
43      XFree 4.0.2 I128
44        -XDGASetMode(..., ..., 0) does *not* return to initial screen mode
45        -grabbing keyboard and mouse does not work, unless sleep(1) first
46        -framebuffer height is incorrectly reported as that of single a screen
47        -XDGA events are not being seen (see #ifdef DGAXXX)
48        -Expose events are not sent in DGA mode
49        -EnterNotify is sent, instead, *most* of the time
50        -look for "pro_nine_workaround"
51 */
52 
53 #ifdef PRO
54 
55 #include <X11/Xlib.h>
56 #include <X11/Xutil.h>
57 #include <X11/keysym.h>
58 #ifdef SHM
59 #include <X11/extensions/XShm.h>
60 #include <sys/ipc.h>
61 #include <sys/shm.h>
62 #endif
63 #ifdef DGA
64 #include <X11/extensions/xf86dga.h>
65 #ifndef DGA2
66 #include <X11/extensions/xf86vmode.h>
67 #endif
68 #include <unistd.h>
69 #endif
70 #include <stdio.h>
71 #include <stdlib.h>
72 #include <string.h>
73 #include <signal.h>
74 #include <math.h>
75 
76 #include "pro_defs.h"
77 #include "pro_lk201.h"
78 
79 
80 #define	PRO_KEYBOARD_FIFO_DEPTH	1024
81 
82 int			pro_nine_workaround = 0;	/* workaround for #9 Xserver bugs */
83 int			pro_libc_workaround = 0;	/* workaround for pre-glibc-2.0 bug */
84 int			pro_window_x = 0;		/* window x position */
85 int			pro_window_y = 0;		/* window y position */
86 int			pro_screen_full = 0;		/* 0 = window, 1 = full-screen */
87 int			pro_screen_window_scale = 2;	/* vertical window scale factor */
88 int			pro_screen_full_scale = 3;	/* vertical DGA scale factor */
89 int			pro_screen_gamma = 10;		/* 10x gamma correction factor */
90 int			pro_screen_pcm = 1;		/* 0 = don't use PCM, 1 = use PCM (private color map) */
91 int			pro_screen_framebuffers = 0;	/* number of DGA framebuffers (1..3 or 0 to auto-detect) */
92 
93 LOCAL int		pro_screen_open = 0;
94 LOCAL int		pro_screen_winheight;		/* height of framebuffer */
95 LOCAL int		pro_screen_bufheight;		/* height of allocated framebuffer */
96 LOCAL int		pro_screen_updateheight;	/* height to update */
97 
98 LOCAL int		pro_keyboard_fifo_h;		/* FIFO head pointer */
99 LOCAL int		pro_keyboard_fifo_t;		/* FIFO tail pointer */
100 LOCAL int		pro_keyboard_fifo[PRO_KEYBOARD_FIFO_DEPTH];
101 
102 int			pro_mouse_x = 0;		/* mouse x */
103 int			pro_mouse_y = 0;		/* mouse y */
104 int			pro_mouse_l = 0;		/* left mouse button */
105 int			pro_mouse_m = 0;		/* middle mouse button */
106 int			pro_mouse_r = 0;		/* right mouse button */
107 int			pro_mouse_in = 0;		/* mouse in window */
108 
109 LOCAL Display		*ProDisplay;			/* pointer to the display */
110 LOCAL int		ProScreen;
111 LOCAL Window		ProWindow;			/* window structure */
112 LOCAL GC		ProGC;
113 LOCAL Colormap		ProColormap;
114 LOCAL XColor		ProColor_map[8];
115 LOCAL XColor		ProColor_nonmap[8];
116 LOCAL int 		ProDepth;			/* color depth */
117 
118 const long 		ProEventMask = ExposureMask | KeyPressMask
119 	                               | KeyReleaseMask | PointerMotionMask
120 	                               | ButtonPressMask | ButtonReleaseMask
121 	                               | EnterWindowMask | LeaveWindowMask;
122 
123 LOCAL unsigned long	ProWhitePixel;
124 LOCAL unsigned long	ProBlackPixel;
125 
126 #ifdef DGA
127 #ifdef DGA2
128 LOCAL int		pro_vid_dga_eventbase;
129 LOCAL int		pro_vid_dga_errorbase;
130 #else
131 LOCAL XF86VidModeModeInfo	pro_modeline;
132 #endif
133 LOCAL char		*pro_vid_dga_addr;
134 LOCAL int		pro_vid_dga_width;
135 LOCAL int		pro_vid_dga_height;
136 #ifndef DGA2
137 LOCAL int		pro_vid_dga_banksize;
138 #endif
139 LOCAL int		pro_vid_dga_memsize;
140 LOCAL Cursor		ProBlankCursor;
141 LOCAL XColor		ProBlackColor;
142 LOCAL int		pro_old_scroll;			/* used to determine when to scroll */
143 LOCAL int		pro_menu_scroll;		/* scroll position when menu is first turned on in DGA mode */
144 LOCAL int		pro_old_overlay_on;		/* used to determine when overlay has been turned off */
145 LOCAL int		pro_mouse_y_screen = 0;
146 #endif
147 
148 LOCAL XImage		*pro_image;
149 
150 LOCAL XKeyboardControl	pro_keyboard_control;
151 LOCAL XKeyboardState	pro_keyboard_state;		/* state to be restored on exit */
152 LOCAL unsigned char	pro_keyboard_keys[32];		/* key vector */
153 
154 LOCAL unsigned char	*pro_image_data;
155 LOCAL int		pro_image_stride;
156 
157 LOCAL int		pro_screen_clutmode;		/* indicates whether window is in CLUT mode */
158 LOCAL int		pro_screen_pixsize;		/* bytes per pixel */
159 LOCAL int		pro_screen_pixsize_act;		/* active bytes per pixel */
160 LOCAL int		pro_screen_clsize;		/* screen cache line size in bytes */
161 LOCAL int		pro_screen_blank = 0;		/* indicates whether screen is blanked */
162 
163 LOCAL int		pro_mask_r;			/* mask for red bits */
164 LOCAL int		pro_mask_g;			/* mask for green bits */
165 LOCAL int		pro_mask_b;			/* mask for blue bits */
166 LOCAL int		pro_nonmap[8];			/* EBO non-mapped colors */
167 LOCAL int		pro_colormap[8];		/* 8-entry colormap for EBO */
168 LOCAL int		*pro_lut;			/* points to nonmap or colormap */
169 
170 #ifdef SHM
171 LOCAL int		shm_present = 1;		/* indicates whether XShm may be used */
172 
173 LOCAL XShmSegmentInfo	shminfo;
174 
175 LOCAL int (*OldXErrorHandler)(Display*, XErrorEvent*);
176 
XShmErrorHandler(Display * dpy,XErrorEvent * xev)177 LOCAL int XShmErrorHandler(Display *dpy, XErrorEvent *xev)
178 {
179   char error[256];
180 
181   XGetErrorText(dpy, xev->error_code, error, 255); error[255] = '\0';
182   fprintf(stderr, "warning: can't use Shm - %s\r\n", error);
183   shm_present = 0;
184   return 0;
185 }
186 #endif
187 
188 LOCAL char* current_title = NULL;
189 LOCAL int title_needs_update = 0;
190 
191 
192 /* Put a title on the display window */
193 
pro_screen_title(char * title)194 void pro_screen_title (char *title)
195 {
196           if (current_title)
197 	    free(current_title);
198 
199 	  current_title = strdup(title);
200           title_needs_update = 1;
201 }
202 
203 
pro_screen_clear()204 void pro_screen_clear ()
205 {
206 int		i, j, k;
207 unsigned char	*mptr;
208 
209 
210 	/* Clear image buffer */
211 
212 	mptr = pro_image_data;
213 
214 	for(i=0; i<pro_screen_bufheight;
215 	    i++, mptr += pro_image_stride*pro_screen_pixsize)
216 	  for(j=0; j<PRO_VID_SCRWIDTH; j++)
217 	    for(k=0; k<pro_screen_pixsize; k++)
218 	      *mptr++ = ProBlackPixel >> (8*k);
219 }
220 
221 
222 /* Save and restore keyboard control settings */
223 
pro_screen_save_old_keyboard()224 void pro_screen_save_old_keyboard ()
225 {
226 	XGetKeyboardControl(ProDisplay, &pro_keyboard_state);
227 }
228 
229 
pro_screen_restore_old_keyboard()230 void pro_screen_restore_old_keyboard ()
231 {
232 XKeyboardControl	key_control;
233 
234 
235 	key_control.bell_pitch = (int)pro_keyboard_state.bell_pitch;
236 	key_control.bell_duration = (int)pro_keyboard_state.bell_duration;
237 	key_control.bell_percent = pro_keyboard_state.bell_percent;
238 	key_control.key_click_percent = pro_keyboard_state.key_click_percent;
239 	key_control.auto_repeat_mode = pro_keyboard_state.global_auto_repeat;
240 
241 	XChangeKeyboardControl(ProDisplay, KBAutoRepeatMode | KBKeyClickPercent
242 	                       | KBBellPitch | KBBellDuration | KBBellPercent,
243 	                       &key_control);
244 }
245 
246 
pro_screen_restore_keyboard()247 void pro_screen_restore_keyboard ()
248 {
249 	if (pro_mouse_in == 1)
250 	  XChangeKeyboardControl(ProDisplay, KBAutoRepeatMode | KBKeyClickPercent
251 	                         | KBBellPitch | KBBellDuration | KBBellPercent,
252 	                         &pro_keyboard_control);
253 }
254 
255 
256 /* Keycode lookup routine (key press) */
257 
pro_keyboard_lookup_down(int xkey)258 LOCAL int pro_keyboard_lookup_down (int xkey)
259 {
260 	switch (xkey)
261 	{
262 	  case XK_Escape:	return PRO_LK201_HOLD;
263 	  case XK_F1:		return PRO_LK201_PRINT;
264 	  case XK_F2:		return PRO_LK201_SETUP;
265 	  case XK_F3:		return PRO_LK201_FFOUR;
266 	  case XK_F4:		return PRO_LK201_BREAK;
267 	  case XK_F5:		return PRO_LK201_INT;
268 	  case XK_F6:		return PRO_LK201_RESUME;
269 	  case XK_F7:		return PRO_LK201_CANCEL;
270 	  case XK_F8:		return PRO_LK201_MAIN;
271 	  case XK_F9:		return PRO_LK201_EXIT;
272 	  case XK_F10:		return PRO_LK201_ESC;
273 	  case XK_F11:		return PRO_LK201_BS;
274 	  case XK_F12:		return PRO_LK201_LF;
275 	  case XK_Num_Lock: /* XXX temp., since Sys_Req is broken! */
276 #ifndef XK_Sys_Req
277 #define XK_Sys_Req 0xFF15
278 #endif
279 	  case XK_Sys_Req:	return PRO_LK201_ADDOP; /* XXX seems broken */
280 	  case XK_Multi_key:	return PRO_LK201_HELP; /* XXX check this! */
281 	  case XK_Pause:	return PRO_LK201_DO;
282 
283 	  case XK_a:		return PRO_LK201_A;
284 	  case XK_b:		return PRO_LK201_B;
285 	  case XK_c:		return PRO_LK201_C;
286 	  case XK_d:		return PRO_LK201_D;
287 	  case XK_e:		return PRO_LK201_E;
288 	  case XK_f:		return PRO_LK201_F;
289 	  case XK_g:		return PRO_LK201_G;
290 	  case XK_h:		return PRO_LK201_H;
291 	  case XK_i:		return PRO_LK201_I;
292 	  case XK_j:		return PRO_LK201_J;
293 	  case XK_k:		return PRO_LK201_K;
294 	  case XK_l:		return PRO_LK201_L;
295 	  case XK_m:		return PRO_LK201_M;
296 	  case XK_n:		return PRO_LK201_N;
297 	  case XK_o:		return PRO_LK201_O;
298 	  case XK_p:		return PRO_LK201_P;
299 	  case XK_q:		return PRO_LK201_Q;
300 	  case XK_r:		return PRO_LK201_R;
301 	  case XK_s:		return PRO_LK201_S;
302 	  case XK_t:		return PRO_LK201_T;
303 	  case XK_u:		return PRO_LK201_U;
304 	  case XK_v:		return PRO_LK201_V;
305 	  case XK_w:		return PRO_LK201_W;
306 	  case XK_x:		return PRO_LK201_X;
307 	  case XK_y:		return PRO_LK201_Y;
308 	  case XK_z:		return PRO_LK201_Z;
309 
310 	  case XK_0:		return PRO_LK201_0;
311 	  case XK_1:		return PRO_LK201_1;
312 	  case XK_2:		return PRO_LK201_2;
313 	  case XK_3:		return PRO_LK201_3;
314 	  case XK_4:		return PRO_LK201_4;
315 	  case XK_5:		return PRO_LK201_5;
316 	  case XK_6:		return PRO_LK201_6;
317 	  case XK_7:		return PRO_LK201_7;
318 	  case XK_8:		return PRO_LK201_8;
319 	  case XK_9:		return PRO_LK201_9;
320 
321 	  case XK_minus:	return PRO_LK201_MINUS;
322 	  case XK_equal:	return PRO_LK201_EQUAL;
323 	  case XK_bracketleft:	return PRO_LK201_LEFTB;
324 	  case XK_bracketright:	return PRO_LK201_RIGHTB;
325 
326 	  case XK_semicolon:	return PRO_LK201_SEMI;
327 	  case XK_quoteright:	return PRO_LK201_QUOTE;
328 	  case XK_backslash:	return PRO_LK201_BACKSL;
329 	  case XK_comma:	return PRO_LK201_COMMA;
330 	  case XK_period:	return PRO_LK201_PERIOD;
331 	  case XK_slash:	return PRO_LK201_SLASH;
332 	  case XK_quoteleft:	return PRO_LK201_TICK;
333 
334 	  case XK_space:	return PRO_LK201_SPACE;
335 
336 	  case XK_BackSpace:	return PRO_LK201_DEL;
337 	  case XK_Return:	return PRO_LK201_RETURN;
338 	  case XK_Tab:		return PRO_LK201_TAB;
339 
340 	  case XK_Up:		return PRO_LK201_UP;
341 	  case XK_Down:		return PRO_LK201_DOWN;
342 	  case XK_Left:		return PRO_LK201_LEFT;
343 	  case XK_Right:	return PRO_LK201_RIGHT;
344 
345 	  case XK_Find:		return PRO_LK201_FIND;
346 	  case XK_Home:		return PRO_LK201_INSERT;
347 	  case XK_Prior:	return PRO_LK201_REMOVE;
348 	  case XK_Delete:	return PRO_LK201_SELECT;
349 	  case XK_End:		return PRO_LK201_PREV;
350 	  case XK_Next:		return PRO_LK201_NEXT;
351 
352 	  case XK_Caps_Lock:	return PRO_LK201_LOCK;
353 	  case XK_Shift_L:	return PRO_LK201_SHIFT;
354 	  case XK_Shift_R:	return PRO_LK201_SHIFT;
355 	  case XK_Control_L:	return PRO_LK201_CTRL;
356 	  case XK_Control_R:	return PRO_LK201_CTRL;
357 	  case XK_Alt_L:	return PRO_LK201_COMPOSE;
358 
359 	  default:		return PRO_NOCHAR;
360 	}
361 }
362 
363 
364 /* Keycode lookup routine (key release) */
365 
pro_keyboard_lookup_up(int xkey)366 LOCAL int pro_keyboard_lookup_up (int xkey)
367 {
368 	switch (xkey)
369 	{
370 	  case XK_Shift_L:	return PRO_LK201_ALLUPS;
371 	  case XK_Shift_R:	return PRO_LK201_ALLUPS;
372 	  case XK_Control_L:	return PRO_LK201_ALLUPS;
373 	  case XK_Control_R:	return PRO_LK201_ALLUPS;
374 
375 	  default:		return PRO_NOCHAR;
376 	}
377 }
378 
379 
380 /* Put character in keycode FIFO */
381 
pro_keyboard_fifo_put(int key)382 LOCAL void pro_keyboard_fifo_put (int key)
383 {
384 	/* Filter keycodes for commands */
385 
386 	/* This is to avoid changing the menu state while screen is closed */
387 
388 	if (pro_screen_open)
389 	  key = pro_menu(key);
390 
391 	if (key != PRO_NOCHAR)
392 	{
393 	  /* First check if FIFO is full */
394 
395 	  if ((pro_keyboard_fifo_h != (pro_keyboard_fifo_t-1))
396 	      && ((pro_keyboard_fifo_h != (PRO_KEYBOARD_FIFO_DEPTH-1))
397 	          || (pro_keyboard_fifo_t != 0)))
398 	  {
399 	    pro_keyboard_fifo[pro_keyboard_fifo_h] = key;
400 	    pro_keyboard_fifo_h++;
401 	    if (pro_keyboard_fifo_h == PRO_KEYBOARD_FIFO_DEPTH)
402 	      pro_keyboard_fifo_h = 0;
403 	  }
404 	}
405 }
406 
407 
408 /* External keyboard polling routine */
409 
pro_keyboard_get()410 int pro_keyboard_get ()
411 {
412 int	key;
413 
414 
415 	/* Get character from keycode FIFO */
416 
417 	/* Check if FIFO is empty */
418 
419 	if (pro_keyboard_fifo_h == pro_keyboard_fifo_t)
420 	  key = PRO_NOCHAR;
421 	else
422 	{
423 	  key = pro_keyboard_fifo[pro_keyboard_fifo_t];
424 	  pro_keyboard_fifo_t++;
425 	  if (pro_keyboard_fifo_t == PRO_KEYBOARD_FIFO_DEPTH)
426 	    pro_keyboard_fifo_t = 0;
427 	}
428 
429 	return key;
430 }
431 
432 
433 /* Save keymap */
434 
pro_screen_save_keys()435 void pro_screen_save_keys ()
436 {
437 int		i;
438 unsigned char	keys[32];
439 
440 
441 	XQueryKeymap(ProDisplay, keys);
442 
443 	for(i=0; i<32; i++)
444 	  pro_keyboard_keys[i] = keys[i];
445 }
446 
447 
448 /* Bring emulator state up to date with shift/ctrl key state that may have changed
449    while focus was lost */
450 
pro_screen_update_keys()451 void pro_screen_update_keys ()
452 {
453 int		i, key, oldkey, curkey;
454 unsigned char	keys[32];
455 
456 
457 	XQueryKeymap(ProDisplay, keys);
458 
459 	for(i=0; i<32*8; i++)
460 	{
461 	  oldkey = pro_keyboard_keys[i/8]&(1<<(i%8));
462 	  curkey = keys[i/8]&(1<<(i%8));
463 
464 	  if (oldkey != curkey)
465 	  {
466 	    key = XKeycodeToKeysym(ProDisplay, i, 0);
467 
468 	    if (curkey == 0)
469 	      key = pro_keyboard_lookup_up(key);
470 	    else
471 	      key = pro_keyboard_lookup_down(key);
472 
473 	    if ((key == PRO_LK201_SHIFT) || (key == PRO_LK201_CTRL)
474 	        || (key == PRO_LK201_ALLUPS))
475 	      pro_keyboard_fifo_put(key);
476 	  }
477 	}
478 }
479 
480 
481 /* Initialize the display */
482 
pro_screen_init()483 int pro_screen_init ()
484 {
485 XSetWindowAttributes	ProWindowAttributes;	/* structure of window attibutes */
486 unsigned long		ProWindowMask;		/* mask for window attributes */
487 XSizeHints		ProSizeHints;		/* window hints for window manger */
488 int			x, y;			/* window position */
489 int 			border_width = 0;	/* border width of the window */
490 
491 XGCValues		ProGCValues;
492 
493 int			i, index;
494 
495 unsigned long		planeret[8];
496 unsigned long		pixret[8];
497 
498 XEvent			event;
499 Window			focus_window;
500 int			revert_to;
501 #ifdef DGA
502 int			old_uid = geteuid();
503 #endif
504 
505 
506 	if (pro_screen_open == 0)
507 	{
508 #ifndef DGA
509 	  if (pro_screen_full)
510 	  {
511 	    printf("Emulator not compiled with DGA support!\r\n");
512 	    return PRO_FAIL;
513 	  }
514 #endif
515 
516 	  /* Set window coordinates */
517 
518 	  x = pro_window_x;
519 	  y = pro_window_y;
520 
521 	  ProDisplay = XOpenDisplay ("");
522 	  if (ProDisplay == NULL)
523 	  {
524 	    fprintf (stderr,
525 	      "ERROR: Could not open a connection to X on display %s\r\n",
526 	      XDisplayName (NULL));
527 	    return PRO_FAIL;
528 	  }
529 
530 	  ProScreen = DefaultScreen (ProDisplay);
531 
532 	  ProDepth = DefaultDepth (ProDisplay, ProScreen);
533 
534 	  ProWhitePixel = WhitePixel(ProDisplay, ProScreen);
535 	  ProBlackPixel = BlackPixel(ProDisplay, ProScreen);
536 
537 	  ProWindowAttributes.border_pixel = BlackPixel (ProDisplay, ProScreen);
538 	  ProWindowAttributes.background_pixel = BlackPixel (ProDisplay, ProScreen);
539 	  ProWindowAttributes.override_redirect = False;
540 	  ProWindowAttributes.event_mask = ProEventMask;
541 
542 	  ProWindowMask = CWEventMask | CWBackPixel | CWBorderPixel;
543 
544 #ifdef DGA
545 	  if (pro_screen_full)
546 	  {
547 	    int modecount;
548 #ifdef DGA2
549 	    XDGADevice	*dgadevice;
550 	    XDGAMode	*dgamode;
551 #else
552 	    int clk;
553 	    XF86VidModeModeLine	ml;
554 	    XF86VidModeModeInfo	**modesinfo;
555 #endif
556 
557 	    if (seteuid(0) != 0)
558 	    {
559 	      printf("DGA error: emulator must be run as root or setuid root\r\n");
560 	      return PRO_FAIL;
561 	    }
562 
563 #ifdef DGA2
564 	    XDGAOpenFramebuffer(ProDisplay, ProScreen);
565 	    dgamode = XDGAQueryModes(ProDisplay, ProScreen, &modecount);
566 
567 	    for(i=0; i<modecount; i++)
568 	      if ((dgamode[i].viewportWidth == PRO_VID_SCRWIDTH)
569 	          && (dgamode[i].viewportHeight == pro_screen_full_scale*PRO_VID_SCRHEIGHT))
570 	        break;
571 	    XFree(dgamode);
572 
573 	    if (i == modecount)
574 	    {
575 	      printf("DGA2 Error - unable to find correct screen mode\r\n");
576 	      printf("%d x %d viewport required\r\n", PRO_VID_SCRWIDTH, pro_screen_full_scale*PRO_VID_SCRHEIGHT);
577 	      seteuid(old_uid);
578 	      return PRO_FAIL;
579 	    }
580 
581 	    dgadevice = XDGASetMode(ProDisplay, ProScreen, i+1);
582 
583             pro_vid_dga_addr = dgadevice -> data;
584             pro_vid_dga_width = (dgadevice -> mode).imageWidth;
585             pro_vid_dga_height = (dgadevice -> mode).imageHeight;
586 
587 	    if (pro_nine_workaround)
588 	    {
589 	      /* This is a workaround for a #9 DGA2 bug that reports
590 	         framebuffer height incorrectly as that of a single screen */
591 
592 	      if (pro_vid_dga_height <= 1024)
593 	        pro_vid_dga_height = 2304;
594 	    }
595 
596             pro_vid_dga_memsize = pro_vid_dga_height * (dgadevice -> mode).bytesPerScanline / 1024;
597 	    XFree(dgadevice);
598 
599 #ifdef DGAXXX
600 	    /* XXX Does not seem to pass DGA events ???  Use XEvents for now... */
601 
602 	    XDGASelectInput(ProDisplay, ProScreen, ProEventMask);
603 #endif
604 	    XDGAQueryExtension(ProDisplay, &pro_vid_dga_eventbase, &pro_vid_dga_errorbase);
605 
606 #else /* DGA1 */
607 
608 	    /* Get current screen mode */
609 
610 	    XF86VidModeGetModeLine(ProDisplay, ProScreen, &clk, &ml);
611 	    if (ml.privsize != 0)
612 	      XFree(ml.private);
613 
614 	    /* Attempt to find appropriate screen mode */
615 
616 	    XF86VidModeGetAllModeLines(ProDisplay, ProScreen, &modecount, &modesinfo);
617 
618 	    for(i=0; i<modecount; i++)
619 	      if ((modesinfo[i]->hdisplay == PRO_VID_SCRWIDTH)
620 	          && (modesinfo[i]->vdisplay == pro_screen_full_scale*PRO_VID_SCRHEIGHT))
621 	        break;
622 
623 	    if (i == modecount)
624 	    {
625 	      printf("DGA1 Error - unable to find correct screen mode\r\n");
626 	      printf("%d x %d viewport required\r\n", PRO_VID_SCRWIDTH, pro_screen_full_scale*PRO_VID_SCRHEIGHT);
627 	      seteuid(old_uid);
628 	      return PRO_FAIL;
629 	    }
630 
631 	    /* Save current screen mode */
632 
633 	    memset(&pro_modeline, 0, sizeof(pro_modeline));
634 
635 	    pro_modeline.dotclock = clk;
636 	    pro_modeline.hdisplay = ml.hdisplay;
637 	    pro_modeline.hsyncstart = ml.hsyncstart;
638 	    pro_modeline.hsyncend = ml.hsyncend;
639 	    pro_modeline.htotal = ml.htotal;
640 	    pro_modeline.vdisplay = ml.vdisplay;
641 	    pro_modeline.vsyncstart = ml.vsyncstart;
642 	    pro_modeline.vsyncend = ml.vsyncend;
643 	    pro_modeline.vtotal = ml.vtotal;
644 	    pro_modeline.flags = ml.flags;
645 
646 	    /* XXX Blank screen here */
647 
648 	    /* Switch screen mode */
649 
650 	    XF86VidModeSwitchToMode(ProDisplay, ProScreen, modesinfo[i]);
651 
652 	    /* XXX is this correct? */
653 
654 	    for(i=0; i<modecount; i++)
655 	    if (modesinfo[i]->privsize != 0)
656 	      XFree(modesinfo[i]->private);
657 
658 	    XFree(modesinfo); /* XXX correct? */
659 
660 	    /* Get frame buffer parameters */
661 
662             XF86DGAGetVideo(ProDisplay, ProScreen,
663 	                    &pro_vid_dga_addr,
664 	                    &pro_vid_dga_width,
665 	                    &pro_vid_dga_banksize,
666 	                    &pro_vid_dga_memsize);
667 
668 	    /* Enter DGA mode */
669 
670 	    XF86DGADirectVideo(ProDisplay, ProScreen,
671 	                       XF86DGADirectGraphics
672 	                       | XF86DGADirectMouse
673 	                       | XF86DGADirectKeyb);
674 #endif
675 
676 	    seteuid(old_uid);
677 
678 	    x = 0;
679 	    y = 0;
680 	  }
681 #endif
682 
683 	  /* Determine pixel depth */
684 /* XXX
685 	  printf("%d bpp\r\n", ProDepth);
686 */
687 
688 	  /* XXX use better technique to detect CLUT modes */
689 
690 	  switch(ProDepth)
691 	  {
692 	    case 8:
693 	      pro_screen_clutmode = 1;
694 	      pro_screen_pixsize = 1;
695 	      pro_screen_pixsize_act = 1;
696 	      break;
697 
698 	    case 12:
699 	      pro_screen_clutmode = 1;
700 	      pro_screen_pixsize = 2;
701 	      pro_screen_pixsize_act = 2;
702 	      break;
703 
704 	    case 15:
705 	    case 16:
706 	      pro_screen_clutmode = 0;
707 	      pro_screen_pixsize = 2;
708 	      pro_screen_pixsize_act = 2;
709 	      break;
710 
711 	    case 24:
712 	      pro_screen_clutmode = 0;
713 	      pro_screen_pixsize = 4;
714 	      pro_screen_pixsize_act = 3;
715 	      break;
716 
717 	    default:
718 	      printf("Unsupported pixel depth\r\n");
719 	      return PRO_FAIL;
720 	  }
721 
722 #ifdef DGA
723 	  if (pro_screen_full)
724 	  {
725 	    /* Check if number of framebuffers should be auto-detected */
726 
727 	    if (pro_screen_framebuffers == 0)
728 	    {
729 	      pro_screen_framebuffers = (pro_vid_dga_memsize*1024) /
730 	        (pro_vid_dga_width*pro_screen_pixsize*pro_screen_full_scale*PRO_VID_MEMHEIGHT);
731 
732 	      if (pro_screen_framebuffers > 3)
733 	        pro_screen_framebuffers = 3;
734 
735 	      if (pro_screen_framebuffers < 1)
736 	        pro_screen_framebuffers = 1;
737 
738 	      printf("Auto-detected %d framebuffer", pro_screen_framebuffers);
739 	      if (pro_screen_framebuffers > 1)
740 	        printf("s");
741 	      printf("\r\n");
742 	    }
743 
744 	    pro_screen_bufheight = pro_screen_framebuffers*pro_screen_full_scale*PRO_VID_MEMHEIGHT;
745 	    pro_screen_winheight = pro_screen_bufheight;
746 	    pro_screen_updateheight = PRO_VID_MEMHEIGHT;
747 	  }
748 	  else
749 #endif
750 	  {
751 	    pro_screen_bufheight = PRO_VID_SCRHEIGHT;
752 	    pro_screen_winheight = pro_screen_window_scale*pro_screen_bufheight;
753 	    pro_screen_updateheight = PRO_VID_SCRHEIGHT;
754 	  }
755 
756 
757 	  ProWindow = XCreateWindow (ProDisplay,
758 				RootWindow (ProDisplay, ProScreen),
759 				x, y, PRO_VID_SCRWIDTH, pro_screen_winheight, border_width,
760 				ProDepth, InputOutput, CopyFromParent,
761 				ProWindowMask, &ProWindowAttributes);
762 
763 	  ProSizeHints.flags = PSize | PMinSize | PMaxSize;
764 
765 	  if ((x != 0) && (y != 0))
766 	  {
767 	    ProSizeHints.flags |= PPosition;
768 	    ProSizeHints.x = x;
769 	    ProSizeHints.y = y;
770 	  }
771 
772 	  ProSizeHints.width = ProSizeHints.min_width = ProSizeHints.max_width
773 	    = PRO_VID_SCRWIDTH;
774 	  ProSizeHints.height = ProSizeHints.min_height = ProSizeHints.max_height
775 	    =  pro_screen_winheight;
776 
777 	  XSetNormalHints (ProDisplay, ProWindow, &ProSizeHints);
778 
779 	  ProGC = XCreateGC (ProDisplay,
780                              ProWindow,
781                              (unsigned long) 0,
782                              &ProGCValues);
783 
784 	  /* error... cannot create gc */
785 	  if (ProGC == 0)
786 	  {
787 	    XDestroyWindow(ProDisplay, ProScreen);
788 	    return PRO_FAIL;
789 	  }
790 
791 	  XSetForeground (ProDisplay, ProGC, ProBlackPixel);
792 	  XSetBackground (ProDisplay, ProGC, ProWhitePixel);
793 
794 
795 	  XMapWindow (ProDisplay, ProWindow);
796 
797 	  /* Wait for window to become visible */
798 	  /* XXX #9 server sometimes hangs here with no events */
799 
800 #ifdef DGA
801 #ifdef DGA2
802 	  /* XXX Major #9 hack to account for missing Expose/EnterNotify
803 	     events in DGA mode */
804 
805 	  if (!pro_screen_full || !pro_nine_workaround)
806 #endif
807 #endif
808 	  do
809 	    XNextEvent(ProDisplay, &event);
810 	  while ((event.type != Expose) && (event.type != EnterNotify));
811 
812 	  /* Determine whether window has input focus */
813 
814 #ifdef DGA
815 	  if (pro_screen_full)
816 	    pro_mouse_in = 1;
817 	  else
818 #endif
819 	  {
820 	    XGetInputFocus (ProDisplay, &focus_window, &revert_to);
821 
822 	    if (focus_window == ProWindow)
823 	      pro_mouse_in = 1;
824 	    else
825 	      pro_mouse_in = 0;
826 	  }
827 
828 	  pro_screen_title("Pro 350");
829 
830 	  pro_screen_clsize = PRO_VID_CLS_PIX * pro_screen_pixsize;
831 
832 	  if ((pro_screen_pcm == 1) && (pro_screen_clutmode == 1))
833 
834 	    /* Allocate private colormap */
835 
836 	    ProColormap = XCreateColormap(ProDisplay,
837 				ProWindow,
838 				DefaultVisual(ProDisplay, DefaultScreen(ProDisplay)),
839 				AllocNone);
840 	  else
841 	    /* Use default colormap */
842 
843 	    ProColormap = DefaultColormap(ProDisplay, ProScreen);
844 
845 	  /* Allocate colors */
846 
847 	  /* XXX also, alloc only 2 colors if non-ebo */
848 
849 	  if (pro_screen_clutmode == 1)
850 	    XAllocColorCells(ProDisplay, ProColormap, True, planeret, 0, pixret, 8);
851 
852 	  for(i=0; i<8; i++)
853 	  {
854 	    if (pro_screen_clutmode == 1)
855 	    {
856 	      index = pixret[i];
857 	      ProColor_nonmap[i].pixel = index;
858 	      ProColor_map[i].pixel = index;
859 
860 	      /* Determine whether PRO is in colormapped mode */
861 
862 	      if ((pro_vid_csr & PRO_VID_CME) != 0)
863 	        XStoreColor(ProDisplay, ProColormap, &ProColor_map[i]);
864 	      else
865 	        XStoreColor(ProDisplay, ProColormap, &ProColor_nonmap[i]);
866 
867 	      pro_colormap[i] = index;
868 	      pro_nonmap[i] = index;
869 	    }
870 	    else
871 	    {
872 	      XAllocColor(ProDisplay, ProColormap, &ProColor_nonmap[i]);
873 	      pro_nonmap[i] = ProColor_nonmap[i].pixel;
874 
875 	      XAllocColor(ProDisplay, ProColormap, &ProColor_map[i]);
876 	      pro_colormap[i] = ProColor_map[i].pixel;
877 	    }
878 	  }
879 
880 
881 	  /* Assign RGB mask values (for overlay blending) */
882 
883 	  if (pro_screen_clutmode == 1)
884 	  {
885 	    pro_mask_r = ~0;
886 	    pro_mask_g = 0;
887 	    pro_mask_b = 0;
888 	  }
889 	  else
890 	  {
891 	    pro_mask_r = pro_nonmap[1];
892 	    pro_mask_g = pro_nonmap[2];
893 	    pro_mask_b = pro_nonmap[4];
894 	  }
895 
896 	  XSetWindowColormap(ProDisplay, ProWindow, ProColormap);
897 
898 #if !PRO_EBO_PRESENT
899 	  pro_nonmap[1] = pro_nonmap[7]; /* XXX change this to 1 */
900 #endif
901 
902 	  /* Create image buffer for screen updates */
903 #ifdef DGA
904 	  if (pro_screen_full)
905 	  {
906 	    pro_image_data = pro_vid_dga_addr;
907 	    pro_image_stride = pro_vid_dga_width - PRO_VID_SCRWIDTH;
908 	  }
909 	  else
910 #endif
911 	  {
912 	    pro_image_stride = 0;
913 #ifdef SHM
914 	    if (XShmQueryExtension(ProDisplay))
915 	    {
916 	      /* Use shared memory */
917 
918 	      OldXErrorHandler = XSetErrorHandler(XShmErrorHandler);
919 
920 	      memset(&shminfo, 0, sizeof(shminfo));
921 	      if (!(pro_image = XShmCreateImage(ProDisplay,
922 					      DefaultVisual(ProDisplay, DefaultScreen(ProDisplay)),
923 					      ProDepth,
924 					      ZPixmap,
925 					      NULL,
926 					      &shminfo,
927 					      PRO_VID_SCRWIDTH, PRO_VID_SCRHEIGHT)))
928 	        shm_present = 0;
929 	      else if ((shminfo.shmid =
930 		        shmget(IPC_PRIVATE, pro_image->bytes_per_line*PRO_VID_SCRHEIGHT, IPC_CREAT|0777))==-1)
931 	        shm_present = 0;
932 	      else if ((shminfo.shmaddr = pro_image->data = shmat(shminfo.shmid, 0, 0))==(char*)-1)
933 	        shm_present = 0;
934 	      else
935 	      {
936 	        if (XShmAttach(ProDisplay, &shminfo)==0) shm_present = 0;
937 	        XSync(ProDisplay, True);
938 	        shmctl(shminfo.shmid, IPC_RMID, 0);
939 
940 	        if (!shm_present) shmdt(shminfo.shmaddr);
941 	      }
942 	      if (pro_image && !shm_present) XDestroyImage(pro_image);
943 	      XSync(ProDisplay, True);
944 	      XSetErrorHandler(OldXErrorHandler);
945 	    }
946 	    else shm_present = 0;
947 
948 	    if (shm_present != 0)
949 	      pro_image_data = pro_image->data;
950 	    else
951 #endif /* SHM */
952 	    {
953 	      /* Use non-shared memory */
954 
955 	      pro_image_data = (unsigned char *)malloc(PRO_VID_SCRWIDTH*PRO_VID_SCRHEIGHT*pro_screen_pixsize);
956 
957 	      pro_image = XCreateImage(ProDisplay,
958 			  DefaultVisual(ProDisplay, DefaultScreen(ProDisplay)),
959 			  ProDepth,
960 			  ZPixmap,
961 			  0,
962 			  (char*) pro_image_data,
963 			  PRO_VID_SCRWIDTH, PRO_VID_SCRHEIGHT,
964 			  pro_screen_pixsize*8,
965 			  PRO_VID_CLS_PIX*pro_screen_pixsize);
966 	    }
967 	  }
968 
969 	  /* Save old keyboard state */
970 
971 	  pro_screen_save_old_keyboard ();
972 
973 	  /* Restore emulator keyboard state */
974 
975 	  pro_screen_restore_keyboard();
976 
977 	  XFlush (ProDisplay);
978 
979 	  /* Make emulator state consistent with keyboard state */
980 
981 	  pro_screen_update_keys();
982 
983 
984 	  /* Initialize the overlay frame buffer */
985 
986 	  pro_overlay_init(pro_screen_pixsize, pro_screen_clutmode,
987 	                   (int)ProBlackPixel, (int)ProWhitePixel);
988 
989 	  pro_screen_open = 1;
990 
991 #ifdef DGA
992 	  if (pro_screen_full)
993 	  {
994 	    /* Check if enough video memory */
995 
996 	    if (pro_screen_winheight*pro_vid_dga_width*pro_screen_pixsize
997 	        >  pro_vid_dga_memsize*1024)
998 	    {
999 	      printf("DGA error: not enough video memory! (%d required, only %d present)\r\n",
1000 	              pro_screen_winheight*pro_vid_dga_width*pro_screen_pixsize,
1001 	              pro_vid_dga_memsize*1024);
1002 	      return PRO_FAIL;
1003 	    }
1004 
1005 #ifdef DGA2
1006 	    XDGASetViewport(ProDisplay, ProScreen, 0, 0, XDGAFlipImmediate);
1007 #else
1008 	    XF86DGASetViewPort(ProDisplay, ProScreen, 0, 0);
1009 #endif
1010 
1011 	    /* Turn off X cursor */
1012 
1013 	    ProBlackColor.red = 0;
1014 	    ProBlackColor.green = 0;
1015 	    ProBlackColor.blue = 0;
1016 
1017 	    ProBlankCursor = XCreatePixmapCursor(ProDisplay,
1018 				  XCreatePixmap(ProDisplay, ProWindow, 1, 1, 1),
1019 				  XCreatePixmap(ProDisplay, ProWindow, 1, 1, 1),
1020 				  &ProBlackColor, &ProBlackColor, 0 ,0);
1021 
1022 	    XDefineCursor(ProDisplay, ProWindow, ProBlankCursor);
1023 
1024 #ifdef DGA2
1025 	    if (pro_screen_full)
1026 	      XDGASync(ProDisplay, ProScreen); /* XXX not sure if needed */
1027 
1028 	    /* XXX Keyboard grabbing sometimes fails without this
1029 	       on #9 server */
1030 
1031 	    if (pro_nine_workaround)
1032 	      sleep(1);
1033 #endif
1034 	    /* Grab Keyboard */
1035 
1036 	    if (XGrabKeyboard(ProDisplay, ProWindow, True, GrabModeAsync,
1037 	        GrabModeAsync, CurrentTime) != GrabSuccess)
1038 	    {
1039 	      printf("DGA error: unable to grab keyboard\r\n");
1040 	      return PRO_FAIL;
1041 	    }
1042 
1043 	    /* Grab Mouse */
1044 
1045 	    if (XGrabPointer(ProDisplay, ProWindow, True,
1046 	        PointerMotionMask | ButtonPressMask | ButtonReleaseMask,
1047 	        GrabModeAsync, GrabModeAsync, None, None,
1048 	        CurrentTime) != GrabSuccess)
1049 	    {
1050 	      printf("DGA error: unable to grab mouse\r\n");
1051 	      return PRO_FAIL;
1052 	    }
1053 
1054 	    pro_old_scroll = -2;
1055 	    pro_old_overlay_on = 0;
1056 
1057 	    /* XXX Unblank screen here */
1058 	  }
1059 #endif
1060 	  /* Clear image buffer */
1061 
1062 	  pro_screen_clear();
1063 
1064 	  /* Invalidate display cache */
1065 
1066 	  pro_clear_mvalid();
1067 	}
1068 
1069 	return PRO_SUCCESS;
1070 }
1071 
1072 
pro_screen_close()1073 void pro_screen_close ()
1074 {
1075 /* XXX not currently used - see below
1076 XWindowAttributes	winattr;
1077 */
1078 
1079 
1080 	if (pro_libc_workaround)
1081 	  printf("1 DDD\r\n");
1082 
1083 	if (pro_screen_open)
1084 	{
1085 	  if (pro_libc_workaround)
1086 	    printf("2 DDD\r\n");
1087 
1088 	  pro_screen_open = 0;
1089 
1090 	  /* XXX deallocate colors? */
1091 
1092 	  /* Restore keyboard parameters */
1093 
1094 	  if (pro_libc_workaround)
1095 	    printf("3 DDD\r\n");
1096 
1097 	  if (pro_mouse_in == 1)
1098 	    pro_screen_restore_old_keyboard();
1099 
1100 	  if (pro_libc_workaround)
1101 	    printf("4 DDD\r\n");
1102 
1103 	  /* Save keymap */
1104 
1105 	  pro_screen_save_keys();
1106 
1107 	  if (pro_libc_workaround)
1108 	    printf("5 DDD\r\n");
1109 
1110 
1111 	  /* Close screen */
1112 
1113 #ifdef DGA
1114 	  if (pro_screen_full)
1115 	  {
1116 	    /* XXX Blank screen here */
1117 
1118 	    if (pro_libc_workaround)
1119 	      printf("6 DDD\r\n");
1120 
1121 	    XUngrabKeyboard(ProDisplay, CurrentTime);
1122 
1123 	    if (pro_libc_workaround)
1124 	      printf("7 DDD\r\n");
1125 
1126 	    XUngrabPointer(ProDisplay, CurrentTime);
1127 
1128 	    if (pro_libc_workaround)
1129 	      printf("8 DDD\r\n");
1130 
1131 #ifdef DGA2
1132 	    XDGACloseFramebuffer(ProDisplay, ProScreen);
1133 
1134 	    /* XXX Major #9 hack to return screen to proper mode */
1135 
1136 	    if (pro_nine_workaround)
1137 	      XDGASetMode(ProDisplay, ProScreen, 1);
1138 
1139 	    XDGASetMode(ProDisplay, ProScreen, 0);
1140 #else
1141 	    XF86DGADirectVideo(ProDisplay, ProScreen, 0);
1142 
1143 	    if (pro_libc_workaround)
1144 	      printf("9 DDD\r\n");
1145 
1146 	    XF86VidModeSwitchToMode(ProDisplay, ProScreen, &pro_modeline);
1147 
1148 	    if (pro_libc_workaround)
1149 	      printf("10 DDD\r\n");
1150 #endif
1151 	  }
1152 	  else
1153 #endif
1154 	  {
1155 #ifdef SHM
1156             if (shm_present)
1157             {
1158 	      if (pro_libc_workaround)
1159 	        printf("11 DDD\r\n");
1160 
1161 	      XShmDetach(ProDisplay, &shminfo);
1162 
1163 	      if (pro_libc_workaround)
1164 	        printf("12 DDD\r\n");
1165 
1166 	      XDestroyImage(pro_image);
1167 
1168 	      if (pro_libc_workaround)
1169 	        printf("13 DDD\r\n");
1170 
1171 	      shmdt(shminfo.shmaddr);
1172 
1173 	      if (pro_libc_workaround)
1174 	        printf("14 DDD\r\n");
1175             }
1176             else
1177 #endif
1178 	      XDestroyImage(pro_image);
1179 	  }
1180 
1181 	  /* Save window x, y coordinates */
1182 
1183 /* XXX broken - always returns (0,0)
1184 	  XGetWindowAttributes (ProDisplay, ProWindow, &winattr);
1185 
1186 	  pro_window_x = winattr.x;
1187 	  pro_window_y = winattr.y;
1188 */
1189 
1190 	  if (pro_libc_workaround)
1191 	    printf("15 DDD\r\n");
1192 
1193 	  XFreeGC (ProDisplay, ProGC);
1194 
1195 	  if (pro_libc_workaround)
1196 	    printf("16 DDD\r\n");
1197 
1198 	  XDestroyWindow (ProDisplay, ProWindow);
1199 
1200 	  if (pro_libc_workaround)
1201 	    printf("17 DDD\r\n");
1202 
1203 	  XCloseDisplay (ProDisplay);
1204 
1205 	  if (pro_libc_workaround)
1206 	    printf("18 DDD\r\n");
1207 
1208 	  /* Close the overlay frame buffer */
1209 
1210 	  pro_overlay_close();
1211 
1212 	  if (pro_libc_workaround)
1213 	    printf("19 DDD\r\n");
1214 	}
1215 
1216 	/* XXX Unblank screen here */
1217 }
1218 
1219 
1220 /* Reset routine (called only once) */
1221 
pro_screen_reset()1222 void pro_screen_reset ()
1223 {
1224 int	r, g, b, i;
1225 
1226 
1227 	/* Clear keymap */
1228 
1229 	memset(&pro_keyboard_keys, 0, sizeof(pro_keyboard_keys));
1230 
1231 	/* Reset keyboard control parameters */
1232 
1233 	pro_keyboard_control.bell_pitch = PRO_LK201_BELL_PITCH;
1234 	pro_keyboard_control.bell_duration = PRO_LK201_BELL_DURATION;
1235 	pro_keyboard_control.bell_percent = 100;
1236 	pro_keyboard_control.key_click_percent = 0;
1237 	pro_keyboard_control.auto_repeat_mode = AutoRepeatModeOn;
1238 
1239 	/* Initialize colormaps */
1240 
1241 	for(r=0; r<=1; r++)
1242 	  for(g=0; g<=1; g++)
1243 	    for(b=0; b<=1; b++)
1244 	    {
1245 	      i = (r | (g<<1) | (b<<2));
1246 
1247 	      ProColor_nonmap[i].red = r * 65535;
1248 	      ProColor_nonmap[i].green = g * 65535;
1249 	      ProColor_nonmap[i].blue = b * 65535;
1250 	      ProColor_nonmap[i].flags = DoRed|DoGreen|DoBlue;
1251 
1252 	      ProColor_map[i].red = 0;
1253 	      ProColor_map[i].green = 0;
1254 	      ProColor_map[i].blue = 0;
1255 	      ProColor_map[i].flags = DoRed|DoGreen|DoBlue;
1256 	    }
1257 }
1258 
1259 
1260 /* This function is called whenever the colormap mode changes.
1261    A new X11 colormap is loaded for private colormap modes,
1262    mvalid is cleared otherwise */
1263 
pro_mapchange()1264 void pro_mapchange ()
1265 {
1266 XColor	*ProColor;
1267 
1268 	if (pro_screen_clutmode == 1)
1269 	{
1270 	  if ((pro_vid_csr & PRO_VID_CME) != 0)
1271 	    ProColor = ProColor_map;
1272 	  else
1273 	    ProColor = ProColor_nonmap;
1274 
1275 	  /* XXX only 2 colors for non-ebo */
1276 
1277 	  XStoreColors(ProDisplay, ProColormap, ProColor, 8);
1278 	}
1279 	else
1280 	  pro_clear_mvalid();
1281 }
1282 
1283 /* This writes an 8-bit (3-3-2) RGB value into the PRO's colormap */
1284 
pro_colormap_write(int index,int rgb)1285 void pro_colormap_write (int index, int rgb)
1286 {
1287 unsigned long	pixel;
1288 double		r, g, b;
1289 
1290 #if PRO_EBO_PRESENT
1291 	/* Calculate linear color component values 0.0 - 1.0 */
1292 
1293 	r = (double)((rgb & PRO_VID_R_MASK) >> 5)/7.0;
1294 	g = (double)((rgb & PRO_VID_G_MASK) >> 2)/7.0;
1295 	b = (double)(rgb & PRO_VID_B_MASK)/3.0;
1296 
1297 	/* Perform gamma correction */
1298 
1299 	r = pow(r, 10.0/(double)pro_screen_gamma);
1300 	g = pow(g, 10.0/(double)pro_screen_gamma);
1301 	b = pow(b, 10.0/(double)pro_screen_gamma);
1302 
1303 	ProColor_map[index].red = (int)(r * 65535.0);
1304 	ProColor_map[index].green = (int)(g * 65535.0);
1305 	ProColor_map[index].blue = (int)(b * 65535.0);
1306 
1307 	if (pro_screen_clutmode == 0)
1308 	{
1309 	  /* Free old color */
1310 
1311 	  pixel = pro_colormap[index];
1312 
1313 	  XFreeColors(ProDisplay, ProColormap, &pixel, 1, 0L);
1314 
1315 	  /* Allocate new color */
1316 
1317 	  XAllocColor(ProDisplay, ProColormap, &ProColor_map[index]);
1318 
1319 	  pro_colormap[index] = ProColor_map[index].pixel;
1320 	}
1321 
1322 	/* Check if in colormapped mode */
1323 
1324 	if ((pro_vid_csr & PRO_VID_CME) != 0)
1325 	{
1326 	  if (pro_screen_clutmode == 1)
1327 	  {
1328 	    XStoreColor(ProDisplay, ProColormap, &ProColor_map[index]);
1329 	  }
1330 	  else
1331 	  {
1332 	    /* The cache gets cleared only for non-private colormap X11 modes */
1333 
1334 	    pro_clear_mvalid();
1335 	  }
1336 	}
1337 #endif
1338 
1339 /* XXX
1340 	printf("Colormap write: index = %x rgb = %x colormap = %x\r\n", index, rgb, pro_colormap[index]);
1341 */
1342 }
1343 
1344 
1345 /* This is called whenever the scroll register changes */
1346 
pro_scroll()1347 void pro_scroll ()
1348 {
1349 	/* Clear entire display cache if DGA disabled,
1350 	   or if DGA is using only a single framebuffer */
1351 
1352 #ifdef DGA
1353 	if ((pro_screen_full == 0) || (pro_screen_framebuffers == 1))
1354 #endif
1355 	  pro_clear_mvalid();
1356 }
1357 
1358 
1359 /* Blending functions used for overlays */
1360 
1361 #define blend \
1362   a = pro_overlay_alpha[pnum]; \
1363   na = PRO_OVERLAY_MAXA - a; \
1364   color = (((na*(pro_mask_r&color) + a*(pro_mask_r&opix))/PRO_OVERLAY_MAXA)&pro_mask_r) \
1365           + (((na*(pro_mask_g&color) + a*(pro_mask_g&opix))/PRO_OVERLAY_MAXA)&pro_mask_g) \
1366           + (((na*(pro_mask_b&color) + a*(pro_mask_b&opix))/PRO_OVERLAY_MAXA)&pro_mask_b)
1367 
1368 
1369 /* This is called every emulated vertical retrace */
1370 
pro_screen_update()1371 void pro_screen_update ()
1372 {
1373 int		i, vdata0, vdata1, vdata2, vindex, vpix, vpixs, vpixe, x, y;
1374 int		a, na, opix, pnum, color, cindex;
1375 int		offset, reps;
1376 #ifdef DGA
1377 int		j, cur_scroll, scroll;
1378 #endif
1379 unsigned char	*image_data;
1380 
1381 
1382 	/* Service X events */
1383 
1384 	pro_screen_service_events();
1385 
1386 	image_data = pro_image_data;
1387 
1388 #ifdef DGA
1389 	scroll = -1; /* viewport will be updated if > -1 */
1390 
1391 	if (pro_screen_full && (pro_screen_framebuffers > 1))
1392 	{
1393 	  /* Check if scroll register has changed */
1394 	  /* (only cause screen scroll if overlay is off) */
1395 
1396 	  cur_scroll = pro_vid_scl & 0xff;
1397 
1398 	  offset = (PRO_VID_SCRWIDTH+pro_image_stride)*pro_screen_pixsize
1399 	           *pro_screen_winheight/pro_screen_framebuffers;
1400 
1401 	  reps = 2;
1402 
1403 	  if (pro_overlay_on == 0)
1404 	  {
1405 	    vindex = 0;
1406 
1407 	    /* Restore the viewport position if overlay was just turned off */
1408 	    /* Or scroll viewport if scroll register has changed */
1409 
1410 	    if ((pro_old_overlay_on != 0) || (cur_scroll != pro_old_scroll))
1411 	      scroll = cur_scroll;
1412 	  }
1413 	  else
1414 	  {
1415 	    vindex = vmem(0);
1416 
1417 	    /* Reset the viewport position if overlay was just turned on */
1418 	    /* And force full screen redraw */
1419 
1420 	    if (pro_old_overlay_on == 0)
1421 	    {
1422 	      pro_clear_mvalid();
1423 
1424 	      if (pro_screen_framebuffers == 3)
1425 	        scroll = 2*PRO_VID_MEMHEIGHT;
1426 	      else
1427 	        scroll = pro_menu_scroll = cur_scroll;
1428 	    }
1429 
1430 	    /* If the overlay is on, scroll the screen by redrawing */
1431 
1432 	    if (cur_scroll != pro_old_scroll)
1433 	      pro_clear_mvalid();
1434 
1435 	    /* Use third frame buffer for overlay mode (if enabled) */
1436 	    /* Otherwise, align frame buffer with visible portion of
1437 	       screen when menu was turned on */
1438 
1439 	    if (pro_screen_framebuffers == 3)
1440 	      image_data += 2*offset;
1441 	    else
1442 	      image_data += (PRO_VID_SCRWIDTH+pro_image_stride)
1443 	                    *pro_screen_pixsize*pro_screen_full_scale
1444 	                    *pro_menu_scroll;
1445 	  }
1446 
1447 	  pro_old_scroll = cur_scroll;
1448 	  pro_old_overlay_on = pro_overlay_on;
1449 	}
1450 	else
1451 #endif
1452 	{
1453 	  offset = 0;
1454 	  reps = 1;
1455 	  vindex = vmem(0);
1456 	}
1457 
1458 	/* Check whether screen has been blanked */
1459 
1460 	if ((pro_vid_p1c & PRO_VID_P1_HRS) == PRO_VID_P1_OFF)
1461 	{
1462 	  if (pro_screen_blank == 0)
1463 	  {
1464 	    /* Blank the screen */
1465 
1466 #ifdef DGA
1467 	    if (pro_screen_full)
1468 	      pro_screen_clear();
1469 	    else
1470 #endif
1471 	      XClearWindow(ProDisplay, ProWindow);
1472 
1473 	    pro_screen_blank = 1;
1474 	  }
1475 	}
1476 	else
1477 	{
1478 	  if (pro_screen_blank == 1)
1479 	  {
1480 	    /* Unblank the screen */
1481 
1482 	    pro_clear_mvalid();
1483 	    pro_screen_blank = 0;
1484 	  }
1485 
1486 #if PRO_EBO_PRESENT
1487 	  /* Determine whether system is in color mapped mode */
1488 
1489 	  if ((pro_vid_csr & PRO_VID_CME) != 0)
1490 	    pro_lut = pro_colormap;
1491 	  else
1492 	    pro_lut = pro_nonmap;
1493 #else
1494 	  pro_lut = pro_nonmap;
1495 #endif
1496 
1497 	  /* Redraw portions of screen that have changed */
1498 
1499 	  for(y=0; y<pro_screen_updateheight; y++)
1500 	  {
1501 	    for(x=0; x<PRO_VID_SCRWIDTH; x+=PRO_VID_CLS_PIX)
1502 	    {
1503 	      /* Update screen segment only if display cache is invalid */
1504 
1505 	      if (pro_vid_mvalid[cmem(vindex)] == 0)
1506 	      {
1507 	      if (pro_overlay_on == 0)
1508 #ifdef DGA
1509 	        for(j = 1; j >= (3-2*reps); image_data += j*offset, j -= 2)
1510 	        {
1511 #endif
1512 	          for(i=0; i<(PRO_VID_CLS_PIX/16); i++)
1513 	          {
1514 	            vpixs = i * 16;
1515 	            vpixe = vpixs + 16;
1516 
1517 	            vdata0 = PRO_VRAM[0][vindex+i];
1518 	            vdata1 = PRO_VRAM[1][vindex+i] << 1;
1519 	            vdata2 = PRO_VRAM[2][vindex+i] << 2;
1520 
1521 	            for(vpix=vpixs; vpix<vpixe; vpix++)
1522 	            {
1523 	              cindex = (vdata2 & 04) | (vdata1 & 02) | (vdata0 & 01);
1524 	              color = pro_lut[cindex];
1525 
1526 	              switch(pro_screen_pixsize)
1527 	              {
1528 	                case 1:
1529 	                  image_data[vpix] = color;
1530 	                  break;
1531 	                case 2:
1532 	                  ((unsigned short *)image_data)[vpix] = color;
1533 	                  break;
1534 	                case 4:
1535 	                  ((unsigned int *)image_data)[vpix] = color;
1536 	                  break;
1537 	                default:
1538 	                  break;
1539 	              }
1540 
1541 	              vdata0 = vdata0 >> 1;
1542 	              vdata1 = vdata1 >> 1;
1543 	              vdata2 = vdata2 >> 1;
1544 	            }
1545 	          }
1546 #ifdef DGA
1547 	        }
1548 #endif
1549 	        else
1550 	          /* XXX putting this in a function might speed things up */
1551 
1552 	          for(i=0; i<(PRO_VID_CLS_PIX/16); i++)
1553 	          {
1554 	            vpixs = i * 16;
1555 	            vpixe = vpixs + 16;
1556 
1557 	            vdata0 = PRO_VRAM[0][vindex+i];
1558 	            vdata1 = PRO_VRAM[1][vindex+i] << 1;
1559 	            vdata2 = PRO_VRAM[2][vindex+i] << 2;
1560 
1561 	            for(vpix=vpixs; vpix<vpixe; vpix++)
1562 	            {
1563 	              cindex = (vdata2 & 04) | (vdata1 & 02) | (vdata0 & 01);
1564 	              color = pro_lut[cindex];
1565 
1566 	              pnum = y*PRO_VID_SCRWIDTH+x+vpix;
1567 
1568 	              switch(pro_screen_pixsize)
1569 	              {
1570 	                case 1:
1571 	                  opix = pro_overlay_data[pnum];
1572 	                  blend;
1573 	                  image_data[vpix] = color;
1574 	                  break;
1575 	                case 2:
1576 	                  opix = ((unsigned short *)pro_overlay_data)[pnum];
1577 	                  blend;
1578 	                  ((unsigned short *)image_data)[vpix] = color;
1579 	                  break;
1580 	                case 4:
1581 	                  opix = ((unsigned int *)pro_overlay_data)[pnum];
1582 	                  blend;
1583 	                  ((unsigned int *)image_data)[vpix] = color;
1584 	                  break;
1585 	                default:
1586 	                  break;
1587 	              }
1588 
1589 	              vdata0 = vdata0 >> 1;
1590 	              vdata1 = vdata1 >> 1;
1591 	              vdata2 = vdata2 >> 1;
1592 	            }
1593 	          }
1594 
1595 	        /* Draw cache-line on screen */
1596 #ifdef DGA
1597 	        if (pro_screen_full == 0)
1598 #endif
1599 	        {
1600 #ifdef SHM
1601 		  if (shm_present)
1602 		    XShmPutImage(ProDisplay, ProWindow, ProGC, pro_image, x, y,
1603 		                 x, y*pro_screen_window_scale, PRO_VID_CLS_PIX, 1, False);
1604 		  else
1605 #endif
1606 		    XPutImage(ProDisplay, ProWindow, ProGC, pro_image, x, y,
1607 		              x, y*pro_screen_window_scale, PRO_VID_CLS_PIX, 1);
1608 	        }
1609 
1610 	        /* Mark cache entry valid */
1611 
1612 	        pro_vid_mvalid[cmem(vindex)] = 1;
1613 	      }
1614 
1615 	      vindex = (vindex + (PRO_VID_CLS_PIX/16)) & PRO_VID_VADDR_MASK;
1616 
1617 	      image_data += pro_screen_clsize;
1618 	    }
1619 #ifdef DGA
1620 	    if (pro_screen_full)
1621 	      image_data += ((pro_screen_full_scale-1)*PRO_VID_SCRWIDTH+pro_screen_full_scale*pro_image_stride)*pro_screen_pixsize;
1622 #endif
1623 	  }
1624 
1625 	  XFlush (ProDisplay);
1626 	}
1627 
1628 	/* Check if title needs to be updated */
1629 
1630 	if (title_needs_update)
1631 	{
1632 	  title_needs_update = 0;
1633 #ifdef DGA
1634 /* XXX
1635 	  if (pro_screen_full)
1636 	    printf("%s\r\n", current_title);
1637 */
1638 #endif
1639 	  XStoreName(ProDisplay, ProWindow, current_title);
1640 	  XFlush(ProDisplay);
1641 	}
1642 
1643 #ifdef DGA
1644 	/* Move viewport, if required */
1645 
1646 	if (pro_screen_full)
1647 	{
1648 	  if (scroll >= 0)
1649 #ifdef DGA2
1650 	  {
1651 	    XDGASetViewport(ProDisplay, ProScreen, 0, pro_screen_full_scale*scroll, XDGAFlipImmediate);
1652 
1653 	    /* Wait for viewport update in case XDGAFlipImmediate is not
1654 	       supported */
1655 
1656 	    while(XDGAGetViewportStatus(ProDisplay, ProScreen));
1657 	  }
1658 #else
1659 	    XF86DGASetViewPort(ProDisplay, ProScreen, 0, pro_screen_full_scale*scroll);
1660 #endif
1661 	}
1662 #endif
1663 }
1664 
1665 
1666 /* Set keyboard bell volume */
1667 
pro_keyboard_bell_vol(int vol)1668 void pro_keyboard_bell_vol (int vol)
1669 {
1670 	/* XXX This actually seems to change the duration under Linux!? */
1671 
1672 	/* vol is in the range 0 (loudest) to 7 (softest) */
1673 
1674 	pro_keyboard_control.bell_percent = (100*(7-vol))/7;
1675 
1676 	pro_screen_restore_keyboard();
1677 
1678 	XFlush(ProDisplay);
1679 }
1680 
1681 
1682 /* Sound keyboard bell */
1683 
pro_keyboard_bell()1684 void pro_keyboard_bell ()
1685 {
1686 	XBell(ProDisplay, 0);
1687 	XFlush(ProDisplay);
1688 }
1689 
1690 
1691 /* Turn off auto-repeat */
1692 
pro_keyboard_auto_off()1693 void pro_keyboard_auto_off ()
1694 {
1695 	pro_keyboard_control.auto_repeat_mode = AutoRepeatModeOff;
1696 
1697 	pro_screen_restore_keyboard();
1698 
1699 	XFlush(ProDisplay);
1700 }
1701 
1702 
1703 /* Turn on auto-repeat */
1704 
pro_keyboard_auto_on()1705 void pro_keyboard_auto_on ()
1706 {
1707 	pro_keyboard_control.auto_repeat_mode = AutoRepeatModeOn;
1708 
1709 	pro_screen_restore_keyboard();
1710 
1711 	XFlush(ProDisplay);
1712 }
1713 
1714 
1715 /* Turn off keyclick */
1716 
pro_keyboard_click_off()1717 void pro_keyboard_click_off ()
1718 {
1719 	pro_keyboard_control.key_click_percent = 0;
1720 
1721 	pro_screen_restore_keyboard();
1722 
1723 	XFlush(ProDisplay);
1724 }
1725 
1726 
1727 /* Turn on keyclick */
1728 
pro_keyboard_click_on()1729 void pro_keyboard_click_on ()
1730 {
1731 	pro_keyboard_control.key_click_percent = 100;
1732 
1733 	pro_screen_restore_keyboard();
1734 
1735 	XFlush(ProDisplay);
1736 }
1737 
1738 
1739 /* The following is a workaround for an x11-hang bug under Linux */
1740 
XCheckMaskEvent_nohang(Display * dpy,long event_mask,XEvent * event)1741 int XCheckMaskEvent_nohang(Display* dpy, long event_mask, XEvent* event)
1742 {
1743    static int checkready = 0;
1744    static sigset_t checkmask;
1745    sigset_t oldmask;
1746    Bool event_return;
1747 
1748    if (!checkready)
1749    {
1750       checkready = 1;
1751       sigemptyset(&checkmask);
1752 /*
1753       sigaddset(&checkmask, SIGUSR1);
1754       sigaddset(&checkmask, SIGUSR2);
1755 */
1756       sigaddset(&checkmask, SIGALRM);
1757       /*
1758        * Add any other signals to the mask that might otherwise
1759        * be set off during the XCheckMaskEvent.  It is possible
1760        * that none of this is needed if libX11 is compiled with
1761        * linux libc-6, because a lot of the code in libX11 compiles
1762        * differently with libc-6 (because of improved thread support.)
1763        * Meanwhile, this hack should allow it to work with libc-5.
1764        */
1765    }
1766    sigprocmask(SIG_BLOCK, &checkmask, &oldmask);
1767    event_return = XCheckMaskEvent(dpy, event_mask, event);
1768    sigprocmask(SIG_UNBLOCK, &oldmask, 0);
1769    return event_return;
1770 }
1771 
1772 
1773 /* Service X events */
1774 
pro_screen_service_events()1775 void pro_screen_service_events ()
1776 {
1777 XEvent		event; /* XXX should this be XDGAEvent for DGA2? */
1778 #ifdef DGAXXX
1779 XKeyEvent	keyevent;
1780 #endif
1781 int		expose = 0;
1782 int		key;
1783 int		eventtype;
1784 
1785 
1786 	/* If multiple events are buffered up, flush them all out */
1787 
1788 	/* XXX bug workaround */
1789 
1790 	while (XCheckMaskEvent_nohang(ProDisplay, ProEventMask, (XEvent *)&event))
1791 	{
1792 	  eventtype = event.type;
1793 
1794 #ifdef DGAXXX
1795 	  if (pro_screen_full)
1796 	    eventtype -= pro_vid_dga_eventbase;
1797 #endif
1798 
1799 	  switch (eventtype)
1800 	  {
1801 	    case Expose:
1802 	      expose = 1;
1803 	      break;
1804 
1805 	    case KeyPress:
1806 #ifdef DGAXXX
1807 #ifdef DGA
1808 #ifdef DGA2
1809 	      if (pro_screen_full)
1810 	      {
1811 	        XDGAKeyEventToXKeyEvent((XDGAKeyEvent*)&event.xkey, (XKeyEvent*)&keyevent);
1812 	        key = XLookupKeysym((XKeyEvent*)&keyevent, 0);
1813 	      }
1814               else
1815 #endif
1816 #endif
1817 #endif
1818 	      key = XLookupKeysym((XKeyEvent*)&event, 0);
1819 	      key = pro_keyboard_lookup_down(key);
1820 	      if (key != PRO_NOCHAR)
1821 	        pro_keyboard_fifo_put(key);
1822 	      break;
1823 
1824 	    case KeyRelease:
1825 #ifdef DGAXXX
1826 #ifdef DGA
1827 #ifdef DGA2
1828 	      if (pro_screen_full)
1829 	      {
1830 	        XDGAKeyEventToXKeyEvent((XDGAKeyEvent*)&event.xkey, (XKeyEvent*)&keyevent);
1831 	        key = XLookupKeysym((XKeyEvent*)&keyevent, 0);
1832 	      }
1833               else
1834 #endif
1835 #endif
1836 #endif
1837 	      key = XLookupKeysym((XKeyEvent*)&event, 0);
1838 	      key = pro_keyboard_lookup_up(key);
1839 	      if (key != PRO_NOCHAR)
1840 	        pro_keyboard_fifo_put(key);
1841 	      break;
1842 
1843 	    case MotionNotify:
1844 #ifdef DGA
1845 	      if (pro_screen_full)
1846 	      {
1847 	        /* DGA mouse events are returned as *relative* motion */
1848 
1849 	        pro_mouse_x += ((XMotionEvent*)&event)->x_root;
1850 	        pro_mouse_y_screen += ((XMotionEvent*)&event)->y_root;
1851 	        pro_mouse_y = pro_mouse_y_screen/pro_screen_full_scale;
1852 	        if (pro_mouse_x >= PRO_VID_SCRWIDTH)
1853 	          pro_mouse_x = PRO_VID_SCRWIDTH-1;
1854 	        if (pro_mouse_x < 0)
1855 	          pro_mouse_x = 0;
1856 	        if (pro_mouse_y >= PRO_VID_SCRHEIGHT)
1857 	          pro_mouse_y = PRO_VID_SCRHEIGHT-1;
1858 	        if (pro_mouse_y < 0)
1859 	          pro_mouse_y = 0;
1860 	      }
1861 	      else
1862 #endif
1863 	      {
1864 	        pro_mouse_x = ((XMotionEvent*)&event)->x;
1865 	        pro_mouse_y = (((XMotionEvent*)&event)->y)/pro_screen_window_scale;
1866 	      }
1867 
1868 	      break;
1869 
1870 	    case ButtonPress:
1871 	      switch (((XButtonEvent *)&event)->button)
1872 	      {
1873 	        case Button1:
1874 	          pro_mouse_l = 1;
1875 	          break;
1876 
1877 	        case Button2:
1878 	          pro_mouse_m = 1;
1879 	          break;
1880 
1881 	        case Button3:
1882 	          pro_mouse_r = 1;
1883 	          break;
1884 	      }
1885 	      break;
1886 
1887 	    case ButtonRelease:
1888 	      switch (((XButtonEvent *)&event)->button)
1889 	      {
1890 	        case Button1:
1891 	          pro_mouse_l = 0;
1892 	          break;
1893 
1894 	        case Button2:
1895 	          pro_mouse_m = 0;
1896 	          break;
1897 
1898 	        case Button3:
1899 	          pro_mouse_r = 0;
1900 	          break;
1901 	      }
1902 	      break;
1903 
1904 	    case EnterNotify:
1905 	      if (pro_mouse_in == 0)
1906 	      {
1907 	        pro_screen_save_old_keyboard();
1908 	        pro_mouse_in = 1;
1909 	        pro_screen_restore_keyboard();
1910 	        pro_screen_update_keys();
1911 	      }
1912 	      break;
1913 
1914 	    case LeaveNotify:
1915 	      if (pro_mouse_in == 1)
1916 	      {
1917 	        pro_screen_save_keys();
1918 	        pro_mouse_in = 0;
1919 	        pro_screen_restore_old_keyboard();
1920 	      }
1921 	      break;
1922 	  }
1923 	}
1924 
1925 	/* Check if screen should be updated */
1926 
1927 	if (expose)
1928 	{
1929 	  /* Clear the window */
1930 
1931 	  XClearWindow(ProDisplay, ProWindow);
1932 
1933 	  /* Clear display cache, forcing full update */
1934 
1935 	  pro_clear_mvalid();
1936 	}
1937 }
1938 #endif
1939