1 /*
2     TiMidity++ -- MIDI to WAVE converter and player
3     Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
4     Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program 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 this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 
20     x_sherry.c - Sherry WRD for X Window written by Masanao Izumo
21 */
22 
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif /* HAVE_CONFIG_H */
26 
27 #ifdef ENABLE_SHERRY
28 #include <X11/Xlib.h>
29 #include <X11/Xutil.h>
30 #ifndef NO_STRING_H
31 #include <string.h>
32 #else
33 #include <strings.h>
34 #endif
35 #include <stdlib.h>
36 #include <png.h>
37 
38 #include "timidity.h"
39 #include "common.h"
40 #include "controls.h"
41 #include "wrd.h"
42 #include "aq.h"
43 #include "x_sherry.h"
44 
45 #ifndef XSHM_SUPPORT
46 #if defined(HAVE_XSHMCREATEPIXMAP) && \
47     defined(HAVE_X11_EXTENSIONS_XSHM_H) && \
48     defined(HAVE_SYS_IPC_H) && \
49     defined(HAVE_SYS_SHM_H)
50 #define XSHM_SUPPORT 1
51 #else
52 #define XSHM_SUPPORT 0
53 #endif
54 #endif /* XSHM_SUPPORT */
55 
56 #if XSHM_SUPPORT
57 #include <X11/extensions/XShm.h>
58 #include <sys/ipc.h>
59 #include <sys/shm.h>
60 #endif
61 
62 #define MAX_PLANES		8
63 #define MAX_COLORS		(1<<MAX_PLANES)
64 #define MAX_VIRTUAL_SCREENS	65536
65 #define MAX_PALETTES		256
66 #define MAX_VIRTUAL_PALETTES	65536
67 #define REAL_SCREEN_SIZE_X	640
68 #define REAL_SCREEN_SIZE_Y	480
69 #define CHAR_WIDTH1		8
70 #define CHAR_WIDTH2		16
71 #define CHAR_HEIGHT		16
72 #define SHERRY_MAX_VALUE	65536
73 #define JISX0201 "-*-fixed-*-r-normal--16-*-*-*-*-*-jisx0201.1976-*"
74 #define JISX0208 "-*-fixed-*-r-normal--16-*-*-*-*-*-jisx0208.1983-*"
75 
76 /* (mask & src) | (~mask & dst) equals as Windows API BitBlt ROP 0x00CA0749 */
77 /* #define ROP3_CA0749(ptn, src, dst) (((ptn) & (src)) | (~(ptn) & (dst))) */
78 #define ROP3_CA0749(ptn, src, dst) ((dst) ^ ((ptn) & ((src) ^ (dst))))
79 
80 typedef struct _ImagePixmap
81 {
82     Pixmap		pm;
83     XImage		*im;
84     GC			gc;
85     int			depth;
86 #if XSHM_SUPPORT
87     XShmSegmentInfo	shminfo;
88 #endif /* XSHM_SUPPORT */
89 } ImagePixmap;
90 
91 typedef struct _VirtualScreen
92 {
93     uint16 width, height;
94     uint8 transParent;
95     uint8 data[1]; /* Pseudo 256 color, size = width * height */
96 } VirtualScreen;
97 
98 typedef struct _SherryPaletteEntry
99 {
100     uint8 r;
101     uint8 g;
102     uint8 b;
103 } SherryPaletteEntry;
104 
105 typedef struct _SherryPalette
106 {
107     SherryPaletteEntry entry[MAX_PALETTES];
108 } SherryPalette;
109 
110 
111 static Display	*theDisplay;
112 static int	theScreen;
113 
114 /* real screen */
115 static Window	theWindow;
116 static ImagePixmap *theRealScreen;
117 static Visual	*theVisual;	/* Visual of main window */
118 static Colormap	theColormap;	/* Colormap of main window */
119 static int	theDepth;	/* Depth of main window */
120 static int	theClass;	/* Visual class */
121 static XFontStruct *theFont8;	/* 8bit Font */
122 static XFontStruct *theFont16;	/* 16bit Font */
123 static int lbearing8, lbearing16, ascent8, ascent16;
124 static GC theGC;
125 
126 /* For memory draw string */
127 #define IMAGEBITMAPLEN 40
128 static ImagePixmap *imageBitmap;
129 static int bitmap_drawimage(ImagePixmap *ip, char *sjis_str, int nbytes);
130 
131 
132 static VirtualScreen **virtualScreen; /* MAX_VIRTUAL_SCREENS */
133 static VirtualScreen  *tmpScreen;
134 static VirtualScreen  *alloc_vscreen(int width, int height, int transParent);
135 static void	       free_vscreen(VirtualScreen *scr);
136 
137 #define VSCREEN_PIXEL(scr, x, y) ((scr)->data[(scr)->width * (y) + (x)])
138 
139 static unsigned long basePixel;	/* base pixel */
140 static unsigned long planePixel[MAX_PLANES]; /* plane pixel */
141 static unsigned long palette2Pixel[MAX_COLORS];
142 static int currentPalette;
143 
144 static SherryPalette **virtualPalette; /* MAX_VIRTUAL_PALETTES, ���ۥѥ�å� */
145 static SherryPaletteEntry realPalette[MAX_PALETTES];
146 static uint8 *pseudoImage = NULL; /* For TrueColor */
147 
148 static int draw_ctl_flag = True;
149 static int err_to_stop = 0;
150 
151 
152 /* Image Pixmap */
153 static ImagePixmap *create_image_pixmap(int width, int height, int depth);
154 static void clear_image_pixmap(ImagePixmap *ip, unsigned long pixel);
155 static void free_image_pixmap(ImagePixmap *ip);
156 
157 #if XSHM_SUPPORT
158 static ImagePixmap *create_shm_image_pixmap(int width, int height, int depth);
159 #endif /* XSHM_SUPPORT */
160 
161 static int isRealPaletteChanged, isRealScreenChanged;
162 static int updateClipX1, updateClipY1, updateClipX2, updateClipY2;
163 
164 static int check_range(VirtualScreen *scr, int x1, int y1, int x2, int y2);
165 
166 
try_create_window(Display * disp,int width,int height,int want_class,int want_depth,Visual ** newVisual,Colormap * newColormap)167 static Window try_create_window(Display *disp, int width, int height,
168 				int want_class, int want_depth,
169 				Visual **newVisual,
170 				Colormap *newColormap)
171 {
172     Visual *defVisual;
173     int defScreen;
174     int defDepth;
175 
176     XSetWindowAttributes xswa;
177     unsigned long xswamask;
178     int numvis;
179 
180     defScreen = DefaultScreen(disp);
181     defVisual = DefaultVisual(disp, defScreen);
182     defDepth  = DefaultDepth(disp, defScreen);
183 
184     if(want_class == -1)
185 	want_class = defVisual->class;
186     if(want_depth == -1)
187 	want_depth = defDepth;
188 
189     if(defVisual->class == want_class && defDepth == want_depth)
190 	*newVisual = defVisual;
191     else
192     {
193 	XVisualInfo *vinfo, rvinfo;
194 
195 	rvinfo.class  = want_class;
196 	rvinfo.screen = defScreen;
197 	rvinfo.depth = want_depth;
198 	vinfo = XGetVisualInfo(disp,
199 			       VisualClassMask |
200 			       VisualScreenMask |
201 			       VisualDepthMask,
202 			       &rvinfo, &numvis);
203 	if(vinfo == NULL)
204 	    return None;
205 	if(numvis == 0)
206 	{
207 	    XFree((char *)vinfo);
208 	    return None;
209 	}
210 
211 	*newVisual = vinfo[0].visual;
212     }
213     *newColormap = XCreateColormap(disp,
214 				   RootWindow(disp, defScreen),
215 				   *newVisual, AllocNone);
216 
217     xswa.background_pixel = 0;
218     xswa.border_pixel     = 0;
219     xswa.colormap         = *newColormap;
220     xswamask = CWBackPixel | CWBorderPixel | CWColormap;
221     return XCreateWindow(disp, RootWindow(disp, defScreen),
222 			 0, 0, width, height, 0, want_depth,
223 			 InputOutput, *newVisual, xswamask, &xswa);
224 }
225 
226 
227 /* Create real-screen for Sherry WRD Window
228  * sutable theVisual, theColormap, theDepth, theClass is selected.
229  */
create_main_window(int want_class,int want_depth)230 static Window create_main_window(int want_class, int want_depth)
231 {
232     Window win;
233     int i;
234     struct {
235 	int want_class, want_depth;
236     } target_visuals[] = {
237     {TrueColor, 24},
238     {TrueColor, 32},
239     {TrueColor, 16},
240     {PseudoColor, 8},
241     {-1, -1}};
242 
243     if(want_class != -1)
244     {
245 	win = try_create_window(theDisplay,
246 				REAL_SCREEN_SIZE_X, REAL_SCREEN_SIZE_Y,
247 				want_class, want_depth,
248 				&theVisual, &theColormap);
249 	theClass = want_class;
250 	theDepth = want_depth;
251 	return win;
252     }
253 
254     for(i = 0; target_visuals[i].want_class != -1; i++)
255 	if((win = try_create_window(theDisplay,
256 				    REAL_SCREEN_SIZE_X, REAL_SCREEN_SIZE_Y,
257 				    target_visuals[i].want_class,
258 				    target_visuals[i].want_depth,
259 				    &theVisual, &theColormap)) != None)
260 	{
261 	    theClass = target_visuals[i].want_class;
262 	    theDepth = target_visuals[i].want_depth;
263 	    return win;
264 	}
265 
266     /* Use default visual */
267     if((win = try_create_window(theDisplay,
268 				REAL_SCREEN_SIZE_X, REAL_SCREEN_SIZE_Y,
269 				-1, -1, &theVisual, &theColormap)) != None)
270     {
271 	theClass = theVisual->class;
272 	theDepth = DefaultDepth(theDisplay, theScreen);
273 	return win;
274     }
275     return None;
276 }
277 
createGC(Display * disp,Drawable draw)278 static GC createGC(Display *disp, Drawable draw)
279 {
280     XGCValues gv;
281     gv.graphics_exposures = False;
282     return XCreateGC(disp, draw, GCGraphicsExposures, &gv);
283 }
284 
highbit(unsigned long ul)285 static int highbit(unsigned long ul)
286 {
287     int i;  unsigned long hb;
288     hb = 0x80000000UL;
289     for(i = 31; ((ul & hb) == 0) && i >= 0;  i--, ul<<=1)
290 	;
291     return i;
292 }
293 
trueColorPixel(unsigned long r,unsigned long g,unsigned long b)294 static inline unsigned long trueColorPixel(unsigned long r, /* 0..255 */
295 					   unsigned long g, /* 0..255 */
296 					   unsigned long b) /* 0..255 */
297 {
298     static int rs, gs, bs;
299 
300     if(r == 0xffffffff) /* for initialize */
301     {
302 	rs = 15 - highbit(theVisual->red_mask);
303 	gs = 15 - highbit(theVisual->green_mask);
304 	bs = 15 - highbit(theVisual->blue_mask);
305 	return 0;
306     }
307 
308     r *= 257; /* 0..65535 */
309     g *= 257; /* 0..65535 */
310     b *= 257; /* 0..65535 */
311     if(rs < 0)	r <<= -rs;
312     else	r >>=  rs;
313     if(gs < 0)	g <<= -gs;
314     else	g >>=  gs;
315     if(bs < 0)	b <<= -bs;
316     else	b >>=  bs;
317     r &= theVisual->red_mask;
318     g &= theVisual->green_mask;
319     b &= theVisual->blue_mask;
320 
321     return r | g | b;
322 }
323 
init_palette(void)324 static Bool init_palette(void)
325 {
326     static int first_flag = 1;
327     int i, j;
328     XColor xcolors[MAX_COLORS];
329 
330     if(first_flag)
331     {
332 	first_flag = 0;
333 
334 	if(theClass == TrueColor)
335 	{
336 	    basePixel = 0;
337 	    trueColorPixel(0xffffffff, 0, 0);
338 	    return True;
339 	}
340 
341 	if(!XAllocColorCells(theDisplay, theColormap, False,
342 			     planePixel, MAX_PLANES,
343 			     &basePixel, 1))
344 	    return False;
345     }
346 
347     if(theClass == TrueColor)
348 	return True;
349 
350     for(i = 0; i < MAX_COLORS; i++)
351     {
352 	palette2Pixel[i] = basePixel;
353 	for(j = 0; j < MAX_PLANES; j++)
354 	    if((i & (1 << j)) != 0) palette2Pixel[i] |= planePixel[j];
355     }
356 
357     for(i = 0; i < MAX_COLORS; i++)
358     {
359 	xcolors[i].pixel = palette2Pixel[i];
360 	xcolors[i].red   = 0;
361 	xcolors[i].green = 0;
362 	xcolors[i].blue  = 0;
363 	xcolors[i].flags = DoRed | DoGreen | DoBlue;
364     }
365     XStoreColors(theDisplay, theColormap, xcolors, MAX_COLORS);
366     return True;
367 }
368 
init_font(void)369 static Bool init_font(void)
370 {
371     if((theFont8 = XLoadQueryFont(theDisplay, JISX0201)) == NULL)
372     {
373 	ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: Can't load font", JISX0201);
374 	return False;
375     }
376     if((theFont16 = XLoadQueryFont(theDisplay, JISX0208)) == NULL)
377     {
378 	ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: Can't load font", JISX0208);
379 	XFreeFont(theDisplay, theFont8);
380 	return False;
381     }
382 
383     lbearing8 = theFont8->min_bounds.lbearing;
384     ascent8   = theFont8->max_bounds.ascent;
385     lbearing16 = theFont16->min_bounds.lbearing;
386     ascent16   = theFont16->max_bounds.ascent;
387 
388     return True;
389 }
390 
free_font(void)391 static void free_font(void)
392 {
393     XFreeFont(theDisplay, theFont8);
394     XFreeFont(theDisplay, theFont16);
395 }
396 
397 /* open */
398 /* return:
399  * -1: error
400  *  0: success
401  *  1: already initialized
402  */
x_sry_open(char * opts)403 static int x_sry_open(char *opts)
404 {
405     static Bool error_flag = False;
406     int i;
407     Bool try_pseudo;
408 
409     if(error_flag)
410     {
411 	if(error_flag == -1)
412 	    ctl->cmsg(CMSG_ERROR, VERB_NOISY,
413 		      "Sherry WRD: Can't work because of error");
414 	else if(error_flag == 1) /* Already initialized */
415 	{
416 	    XMapWindow(theDisplay, theWindow);
417 	    clear_image_pixmap(theRealScreen, basePixel);
418 	    XFlush(theDisplay);
419 	    return 0;
420 	}
421 	return error_flag;
422     }
423 
424     try_pseudo = 0;
425     if(opts)
426     {
427 	if(strchr(opts, 'p'))
428 	    try_pseudo = 1;
429     }
430 
431     if((theDisplay = XOpenDisplay(NULL)) == NULL)
432     {
433 	ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
434 		  "Sherry WRD: Can't open display: %s", XDisplayName(NULL));
435 	error_flag = -1;
436 	return -1;
437     }
438 
439     if(!init_font())
440     {
441 	XCloseDisplay(theDisplay);
442 	theDisplay = NULL;
443 	error_flag = -1;
444 	return -1;
445     }
446 
447     theScreen = DefaultScreen(theDisplay);
448     if(try_pseudo)
449 	theWindow = create_main_window(PseudoColor, 8);
450     else
451 	theWindow = create_main_window(-1, -1);
452     if(theWindow == None)
453     {
454 	ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
455 		  "Sherry WRD: Can't create Sherry WRD Window");
456 	free_font();
457 	XCloseDisplay(theDisplay);
458 	theDisplay = NULL;
459 	error_flag = -1;
460 	return -1;
461     }
462     XSelectInput(theDisplay, theWindow, ExposureMask);
463 
464 #if XSHM_SUPPORT
465     theRealScreen = create_shm_image_pixmap(REAL_SCREEN_SIZE_X,
466 					    REAL_SCREEN_SIZE_Y,
467 					    theDepth);
468     imageBitmap = create_shm_image_pixmap(IMAGEBITMAPLEN * CHAR_WIDTH1,
469 					  CHAR_HEIGHT,
470 					  theDepth);
471 #else
472     theRealScreen = create_image_pixmap(REAL_SCREEN_SIZE_X,
473 					REAL_SCREEN_SIZE_Y,
474 					theDepth);
475     imageBitmap = create_image_pixmap(IMAGEBITMAPLEN * CHAR_WIDTH1,
476 				      CHAR_HEIGHT,
477 				      1);
478 #endif
479 
480     init_palette();
481     XSetWindowBackground(theDisplay, theWindow, basePixel);
482     XSetForeground(theDisplay, imageBitmap->gc, 1);
483     XSetBackground(theDisplay, imageBitmap->gc, 0);
484 
485     theGC = createGC(theDisplay, theWindow);
486 
487     virtualScreen = (VirtualScreen **)safe_malloc(MAX_VIRTUAL_SCREENS *
488 						  sizeof(VirtualScreen *));
489     for(i = 0; i < MAX_VIRTUAL_SCREENS; i++)
490 	virtualScreen[i] = NULL;
491     tmpScreen = NULL;
492 
493     virtualPalette = (SherryPalette **)safe_malloc(MAX_VIRTUAL_PALETTES *
494 						   sizeof(SherryPalette *));
495     for(i = 0; i < MAX_VIRTUAL_PALETTES; i++)
496 	virtualPalette[i] = NULL;
497     memset(realPalette, 0, sizeof(realPalette));
498 
499     if(theClass == TrueColor)
500     {
501 	pseudoImage = (uint8 *)safe_malloc(REAL_SCREEN_SIZE_X *
502 					   REAL_SCREEN_SIZE_Y);
503 	memset(pseudoImage, 0, REAL_SCREEN_SIZE_X * REAL_SCREEN_SIZE_Y);
504     }
505 
506     XMapWindow(theDisplay, theWindow);
507     XFlush(theDisplay);
508     error_flag = 1;
509 
510     return 0;
511 }
512 
CloseSryWindow(void)513 void CloseSryWindow(void)
514 {
515     XUnmapWindow(theDisplay, theWindow);
516     XFlush(theDisplay);
517 }
518 
OpenSryWindow(char * opts)519 int OpenSryWindow(char *opts)
520 {
521     return x_sry_open(opts);
522 }
523 
x_sry_close(void)524 void x_sry_close(void)
525 {
526     int i;
527 
528     if(theDisplay == NULL)
529 	return;
530     free_image_pixmap(theRealScreen);
531     free_image_pixmap(imageBitmap);
532     for(i = 0; i < MAX_VIRTUAL_SCREENS; i++)
533 	if(virtualScreen[i] != NULL)
534 	{
535 	    free_vscreen(virtualScreen[i]);
536 	    virtualScreen[i] = NULL;
537 	}
538     free(virtualScreen);
539     if(tmpScreen != NULL)
540     {
541 	free(tmpScreen);
542 	tmpScreen = NULL;
543     }
544     for(i = 0; i < MAX_VIRTUAL_PALETTES; i++)
545 	if(virtualPalette[i] != NULL)
546 	{
547 	    free(virtualPalette[i]);
548 	    virtualPalette[i] = NULL;
549 	}
550     free(virtualPalette);
551     if(pseudoImage)
552 	free(pseudoImage);
553     XFreeFont(theDisplay, theFont8);
554     XFreeFont(theDisplay, theFont16);
555     XCloseDisplay(theDisplay);
556     theDisplay = NULL;
557 }
558 
sry_new_vpal(uint8 * data,int len)559 static void sry_new_vpal(uint8 *data, int len)
560 {
561     int i, n;
562 
563     for(i = 0; i < len-1; i += 2)
564     {
565 	n = SRY_GET_SHORT(data + i) & 0xffff;
566 #ifdef SRY_DEBUG
567 	printf("NEW palette %d\n", n);
568 #endif /* SRY_DEBUG */
569 	if(virtualPalette[n] == NULL)
570 	    virtualPalette[n] =
571 		(SherryPalette *)safe_malloc(sizeof(SherryPalette));
572 	memset(virtualPalette[n], 0, sizeof(SherryPalette));
573     }
574 }
575 
sry_free_vpal(uint8 * data,int len)576 static void sry_free_vpal(uint8 *data, int len)
577 {
578     int i, n;
579 
580     for(i = 0; i < len-1; i += 2)
581     {
582 	n = SRY_GET_SHORT(data + i) & 0xffff;
583 	if(virtualPalette[n] != NULL)
584 	{
585 	    free(virtualPalette[n]);
586 	    virtualPalette[n] = NULL;
587 	}
588     }
589 }
590 
sry_new_vram(uint8 * data,int len)591 static void sry_new_vram(uint8 *data, int len)
592 {
593     int i, n, width, height, c;
594 
595     for(i = 0; i < len-6; i += 7)
596     {
597 	n      = SRY_GET_SHORT(data + i) & 0xffff;
598 	width  = SRY_GET_SHORT(data + i + 2) & 0xffff;
599 	height = SRY_GET_SHORT(data + i + 4) & 0xffff;
600 	c      = data[6];
601 #ifdef SRY_DEBUG
602 	printf("sherry: new vram[%d] %dx%d (t=%d)\n",
603 	       n, width, height, c);
604 #endif /* SRY_DEBUG */
605 
606 	if(virtualScreen[n] != NULL)
607 	    free_vscreen(virtualScreen[n]);
608 	virtualScreen[n] = alloc_vscreen(width, height, c);
609     }
610 }
611 
sry_free_vram(uint8 * data,int len)612 static void sry_free_vram(uint8 *data, int len)
613 {
614     int i, n;
615     for(i = 0; i < len-1; i += 2)
616     {
617 	n = SRY_GET_SHORT(data + i) & 0xffff;
618 	if(virtualScreen[n] != NULL)
619 	{
620 	    free_vscreen(virtualScreen[n]);
621 	    virtualScreen[n] = NULL;
622 	}
623     }
624 }
625 
sry_pal_set(uint8 * data,int len)626 static void sry_pal_set(uint8 *data, int len)
627 {
628     int pg, i, p;
629     SherryPaletteEntry *entry;
630 
631     pg = SRY_GET_SHORT(data) & 0xffff;
632     if(virtualPalette[pg] == NULL)
633     {
634 	ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
635 		  "WRD Sherry: virtual palette %d is not allocated", pg);
636 	err_to_stop = 1;
637 	return;
638     }
639     entry = virtualPalette[pg]->entry;
640     data += 2;
641     len -= 2;
642 
643 #ifdef SRY_DEBUG
644     printf("set palette color of %d (n=%d)\n", pg, len / 4);
645 #endif /* SRY_DEBUG */
646 
647     for(i = 0; i < len - 3; i += 4)
648     {
649 	p = data[i];
650 	entry[p].r = data[i + 1];
651 	entry[p].g = data[i + 2];
652 	entry[p].b = data[i + 3];
653     }
654 }
655 
update_real_screen(int x,int y,int width,int height)656 static void update_real_screen(int x, int y, int width, int height)
657 {
658   if(!draw_ctl_flag)
659     return;
660 #if XSHM_SUPPORT
661     if(theRealScreen->shminfo.shmid != -1)
662     {
663 	XShmPutImage(theDisplay, theWindow, theGC, theRealScreen->im,
664 		     x, y, x, y, width, height, False);
665 	return;
666     }
667 #endif
668 
669     XPutImage(theDisplay, theWindow, theGC, theRealScreen->im,
670 	      x, y, x, y, width, height);
671 }
672 
updateScreen(int sx,int sy,int width,int height)673 static void updateScreen(int sx, int sy, int width, int height)
674 {
675     if(theClass == TrueColor)
676     {
677 	XImage *im;
678 	int x, y, c;
679 	int units_per_line;
680 	unsigned long pixels[MAX_COLORS];
681 
682 	for(c = 0; c < MAX_COLORS; c++)
683 	    pixels[c] = trueColorPixel(realPalette[c].r,
684 				       realPalette[c].g,
685 				       realPalette[c].b);
686 
687 	im = theRealScreen->im;
688 	units_per_line = im->bytes_per_line / (im->bits_per_pixel / 8);
689 
690 	switch(im->bits_per_pixel)
691 	{
692 #if 1
693 	  case 8:
694 	    for(y = 0; y < height; y++)
695 		for(x = 0; x < width; x++)
696 		{
697 		    c = pseudoImage[(sy + y) * REAL_SCREEN_SIZE_X + sx + x];
698 		    im->data[(sy + y) * units_per_line + sx + x] = pixels[c];
699 		}
700 	    break;
701 	  case 16:
702 	    for(y = 0; y < height; y++)
703 		for(x = 0; x < width; x++)
704 		{
705 		    c = pseudoImage[(sy + y) * REAL_SCREEN_SIZE_X + sx + x];
706 		    ((uint16 *)im->data)[(sy + y) * units_per_line + sx + x]
707 			= pixels[c];
708 		}
709 	    break;
710 	  case 32:
711 	    for(y = 0; y < height; y++)
712 		for(x = 0; x < width; x++)
713 		{
714 		    c = pseudoImage[(sy + y) * REAL_SCREEN_SIZE_X + sx + x];
715 		    ((uint32 *)im->data)[(sy + y) * units_per_line + sx + x]
716 			= pixels[c];
717 		}
718 	    break;
719 #endif
720 	  default: /* Generic routine */
721 	    for(y = 0; y < height; y++)
722 		for(x = 0; x < width; x++)
723 		{
724 		    c = pseudoImage[(sy + y) * REAL_SCREEN_SIZE_X + sx + x];
725 		    XPutPixel(theRealScreen->im, sx + x, sy + y, pixels[c]);
726 		}
727 	    break;
728 	}
729     }
730 
731     update_real_screen(sx, sy, width, height);
732     isRealScreenChanged = 0;
733 }
734 
updatePalette(void)735 static void updatePalette(void)
736 {
737     int i;
738     XColor xc[256];
739 
740     if(theClass != TrueColor)
741     {
742 	for(i = 0; i < MAX_COLORS; i++)
743 	{
744 	    xc[i].pixel = palette2Pixel[i];
745 	    xc[i].red   = realPalette[i].r * 257;
746 	    xc[i].green = realPalette[i].g * 257;
747 	    xc[i].blue  = realPalette[i].b * 257;
748 	    xc[i].flags = DoRed | DoGreen | DoBlue;
749 	}
750 	XStoreColors(theDisplay, theColormap, xc, MAX_COLORS);
751     }
752     else /* True color */
753     {
754 	updateScreen(0, 0, REAL_SCREEN_SIZE_X, REAL_SCREEN_SIZE_Y);
755 	isRealScreenChanged = 0;
756     }
757     isRealPaletteChanged = 0;
758 }
759 
760 
sry_pal_v2r(uint8 * data)761 static void sry_pal_v2r(uint8 *data)
762 {
763     int n;
764     n = SRY_GET_SHORT(data) & 0xffff;
765 
766 #ifdef SRY_DEBUG
767     printf("Transfer palette %d\n", n);
768 #endif /* SRY_DEBUG */
769 
770     if(virtualPalette[n] == NULL)
771     {
772 	virtualPalette[n] =
773 	    (SherryPalette *)safe_malloc(sizeof(SherryPalette));
774 	memset(virtualPalette[n], 0, sizeof(SherryPalette));
775     }
776 
777     memcpy(realPalette, virtualPalette[n]->entry, sizeof(realPalette));
778     isRealPaletteChanged = 1;
779     currentPalette = n;
780 }
781 
png_read_func(png_structp png_ptr,char * buff,size_t n)782 static void png_read_func(png_structp png_ptr, char *buff, size_t n)
783 {
784     struct timidity_file *tf = png_get_io_ptr(png_ptr);
785     tf_read(buff, 1, n, tf);
786 }
787 
788 #define PNG_BYTES_TO_CHECK	8
789 #define MAX_SCREEN_COLORS	256
sry_load_png(uint8 * data)790 static void sry_load_png(uint8 *data)
791 {
792     int i;
793     int x, y;
794     int screen, vpalette;
795     png_structp pngPtr;
796     png_infop infoPtr;
797     png_infop endInfo;
798     VirtualScreen *scr;
799     SherryPaletteEntry *entry;
800 
801     char *filename;
802     struct timidity_file *tf;
803     char sig[PNG_BYTES_TO_CHECK];
804 
805     png_uint_32 width, height;
806     int bitDepth, colorType, interlaceType, compressionType, filterType;
807 
808     int numPalette;
809     png_colorp palette;
810     png_uint_16p hist;
811     png_bytep *rowPointers;
812     png_uint_32 rowbytes;
813     png_bytep trans;
814     int transParent;
815     int numTrans;
816     png_color_16p transValues;
817 
818     numPalette = -1;
819     memset(&palette, 0, sizeof(palette));
820     hist = NULL;
821     rowbytes = 0;
822     rowPointers = NULL;
823     trans = NULL;
824     numTrans = 0;
825     transValues = NULL;
826 
827     screen = SRY_GET_SHORT(data) & 0xffff;
828     vpalette = SRY_GET_SHORT(data + 2) & 0xffff;
829     filename = (char *)data + 4;
830 
831 #ifdef SRY_DEBUG
832     printf("Load png: %s: scr=%d pal=%d\n", filename, screen, vpalette);
833 #endif /* SRY_DEBUG */
834 
835     if((tf = wrd_open_file(filename)) == NULL)
836     {
837 	err_to_stop = 1;
838 	return;
839     }
840     if(tf_read(sig, 1, sizeof(sig), tf) != sizeof(sig))
841     {
842 	ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
843 		  "WRD Sherry: %s is too short to be png format.", filename);
844 	err_to_stop = 1;
845 	return;
846     }
847     if(png_sig_cmp((unsigned char*)sig, 0, sizeof(sig)))
848     {
849 	ctl->cmsg(CMSG_ERROR, VERB_NORMAL, "%s: Not a png file", filename);
850 	err_to_stop = 1;
851 	return;
852     }
853 
854 
855     pngPtr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
856 				    NULL, NULL, NULL);
857     infoPtr = png_create_info_struct(pngPtr);
858     endInfo = png_create_info_struct(pngPtr);
859 
860     png_set_read_fn(pngPtr, (void *)tf, (png_rw_ptr)png_read_func);
861     png_set_sig_bytes(pngPtr, sizeof(sig));
862     png_read_info(pngPtr, infoPtr);
863 
864     /* get info */
865     png_get_IHDR(pngPtr, infoPtr, &width, &height,
866 		 &bitDepth, &colorType,
867 		 &interlaceType, &compressionType, &filterType);
868 
869     /* transformation */
870     /* contert to 256 palette */
871     if (colorType == PNG_COLOR_TYPE_GRAY && bitDepth < 8)
872 	png_set_expand(pngPtr);
873     if(bitDepth == 16)
874 	png_set_strip_16(pngPtr);
875     if(bitDepth < 8)
876 	png_set_packing(pngPtr);
877     if(colorType == PNG_COLOR_TYPE_GRAY ||
878        colorType == PNG_COLOR_TYPE_GRAY_ALPHA)
879 	png_set_gray_to_rgb(pngPtr);
880 
881 #if 0
882   double screenGamma;
883   const char* const gammaStr = getenv ("SCREEN_GAMMA");
884   if (gammaStr != NULL)
885     {
886       screenGamma = atof (gammaStr);
887     }
888   else
889     {
890       screenGamma = 2.2;
891 /*
892       screenGamms = 2.0;
893       screenGamms = 1.7;
894       screenGamms = 1.0;
895 */
896     }
897 
898   if (png_get_gAMA (pngPtr, infoPtr, &gamma))
899     png_set_gamma (pngPtr, screenGamma, gamma);
900   else
901     png_set_gamma (pngPtr, screenGamma, 0.50);
902 #endif
903 
904     if(png_get_valid(pngPtr, infoPtr, PNG_INFO_PLTE))
905     {
906 	png_get_PLTE(pngPtr, infoPtr, &palette, &numPalette);
907 	if(numPalette > MAX_SCREEN_COLORS)
908 	{
909 	    if(png_get_valid(pngPtr, infoPtr, PNG_INFO_hIST))
910 		png_get_hIST(pngPtr, infoPtr, &hist);
911 #if PNG_LIBPNG_VER >= 10402
912 	    png_set_quantize(pngPtr, palette,
913 #else
914 	    png_set_dither(pngPtr, palette,
915 #endif
916 			   numPalette, MAX_SCREEN_COLORS, hist, 1);
917 	}
918     }
919     else
920     {
921 	/* XXX */
922 	/* NOTE 6*7*6 = 252 */
923 	/* 6*7*6 = 5*7*6 + 6*6 + 6 */
924 	png_color stdColorCube[6*7*6];
925 	png_byte r, g, b;
926 
927 	for(r = 0; r < 6; r++)
928 	{
929 	    for(g = 0; g < 7; g++)
930 	    {
931 		for(b = 0; b < 6; b++)
932 		{
933 		    png_byte index = r*7*6+g*6+b;
934 		    stdColorCube[index].red   = r;
935 		    stdColorCube[index].green = g;
936 		    stdColorCube[index].blue  = b;
937 		}
938 	    }
939 	}
940 #if PNG_LIBPNG_VER >= 10402
941 	png_set_quantize(pngPtr, stdColorCube,
942 #else
943 	png_set_dither(pngPtr, stdColorCube,
944 #endif
945 		       6*7*6, MAX_SCREEN_COLORS,
946 		       NULL, 1);
947 	png_get_PLTE(pngPtr, infoPtr, &palette, &numPalette);
948     }
949 
950     if(png_get_valid(pngPtr, infoPtr, PNG_INFO_tRNS))
951 	png_get_tRNS(pngPtr, infoPtr, &trans, &numTrans, &transValues);
952 
953     png_read_update_info(pngPtr, infoPtr);
954 
955     rowbytes = png_get_rowbytes(pngPtr, infoPtr);
956     /* rowbytes == width */
957     rowPointers = (png_bytep *)safe_malloc(height * sizeof(png_bytep));
958     rowPointers[0] = (png_byte *)safe_malloc(rowbytes * height *
959 					     sizeof(png_byte));
960     for(i = 1; i < height; i++)
961 	rowPointers[i] = rowPointers[0] + i * rowbytes;
962 
963     png_read_image(pngPtr, rowPointers);
964     png_read_end(pngPtr, endInfo);
965 
966     if(trans == NULL || numTrans == 0)
967 	transParent = 0;
968     else
969 	transParent = trans[0] & 0xff;
970 
971     scr = virtualScreen[screen];
972     if(scr != NULL && (scr->width != width || scr->height != height))
973     {
974 	free_vscreen(scr);
975 	scr = NULL;
976     }
977     if(scr == NULL)
978 	scr = virtualScreen[screen] =
979 	    alloc_vscreen(width, height*2, transParent);
980     else
981 	scr->transParent = transParent;
982 
983     if(virtualPalette[vpalette] == NULL)
984     {
985 	virtualPalette[vpalette] =
986 	    (SherryPalette *)safe_malloc(sizeof(SherryPalette));
987 	memset(virtualPalette[vpalette], 0, sizeof(SherryPalette));
988     }
989 
990     entry = virtualPalette[vpalette]->entry;
991     for(i = 0; i < numPalette; i++)
992     {
993 	entry[i].r = palette[i].red;
994 	entry[i].g = palette[i].green;
995 	entry[i].b = palette[i].blue;
996     }
997 
998     for(y = 0; y < height; y++)
999 	for(x = 0; x < width; x++)
1000 	    VSCREEN_PIXEL(scr, x, y) = rowPointers[y][x];
1001 
1002     free(rowPointers[0]);
1003     free(rowPointers);
1004     png_destroy_read_struct(&pngPtr, &infoPtr, &endInfo);
1005     close_file(tf);
1006 #ifdef SRY_DEBUG
1007     printf("Load png ok: width=%d height=%d\n", width, height);
1008 #endif /* SRY_DEBUG */
1009 }
1010 
sry_trans_all(uint8 * data)1011 static void sry_trans_all(uint8 *data)
1012 {
1013     int screen, x, y;
1014     int sx, sy;
1015     VirtualScreen *scr;
1016     XImage *im;
1017 
1018     screen = SRY_GET_SHORT(data + 0) & 0xffff;
1019     sx     = SRY_GET_SHORT(data + 2) & 0xffff;
1020     sy     = SRY_GET_SHORT(data + 4) & 0xffff;
1021     im = theRealScreen->im;
1022     scr = virtualScreen[screen];
1023 
1024 #ifdef SRY_DEBUG
1025     printf("Trans all: %d:(%d,%d)\n", screen, sx, sy);
1026 #endif /* SRY_DEBUG */
1027 
1028     if(!check_range(scr, sx, sy,
1029 		    sx + REAL_SCREEN_SIZE_X - 1, sy + REAL_SCREEN_SIZE_Y - 1))
1030 	return;
1031 
1032     if(theClass != TrueColor)
1033     {
1034 	for(y = 0; y < REAL_SCREEN_SIZE_Y; y++)
1035 	    for(x = 0; x < REAL_SCREEN_SIZE_X; x++)
1036 		XPutPixel(im, x, y, VSCREEN_PIXEL(scr, sx + x, sy + y));
1037     }
1038     else /* TrueColor */
1039     {
1040 	for(y = 0; y < REAL_SCREEN_SIZE_Y; y++)
1041 	    memcpy(pseudoImage + y * REAL_SCREEN_SIZE_X,
1042 		   scr->data + (sy + y) * scr->width + sx,
1043 		   REAL_SCREEN_SIZE_X);
1044     }
1045 
1046     isRealScreenChanged = 1;
1047     updateClipX1 = 0;
1048     updateClipY1 = 0;
1049     updateClipX2 = REAL_SCREEN_SIZE_X-1;
1050     updateClipY2 = REAL_SCREEN_SIZE_Y-1;
1051 }
1052 
sry_trans_partial_real(uint8 * data)1053 static void sry_trans_partial_real(uint8 *data)
1054 {
1055     int screen, sx, sy, tx, ty, w, h, x, y;
1056     int x2, y2;
1057     VirtualScreen *scr;
1058     XImage *im;
1059 
1060     screen = SRY_GET_SHORT(data + 0) & 0xffff;
1061     sx     = SRY_GET_SHORT(data + 2) & 0xffff;
1062     sy     = SRY_GET_SHORT(data + 4) & 0xffff;
1063     tx     = SRY_GET_SHORT(data + 6) & 0xffff;
1064     ty     = SRY_GET_SHORT(data + 8) & 0xffff;
1065     w      = SRY_GET_SHORT(data +10) & 0xffff;
1066     h      = SRY_GET_SHORT(data +12) & 0xffff;
1067     x2     = tx + w - 1;
1068     if(x2 >= REAL_SCREEN_SIZE_X)
1069     {
1070 	x2 = REAL_SCREEN_SIZE_X - 1;
1071 	w = x2 - tx + 1;
1072     }
1073     y2     = ty + h - 1;
1074     if(y2 >= REAL_SCREEN_SIZE_Y)
1075     {
1076 	y2 = REAL_SCREEN_SIZE_Y - 1;
1077 	h = y2 - ty + 1;
1078     }
1079 
1080 #ifdef SRY_DEBUG
1081     printf("Trans partial: %d:(%d,%d) (%d,%d) %dx%d\n",
1082 	   screen, sx, sy, tx, ty, w, h);
1083 #endif /* SRY_DEBUG */
1084 
1085     im = theRealScreen->im;
1086     scr = virtualScreen[screen];
1087 
1088     if(theClass != TrueColor)
1089     {
1090 	for(y = 0; y < h; y++)
1091 	    for(x = 0; x < w; x++)
1092 		XPutPixel(im, tx + x, ty + y,
1093 			  VSCREEN_PIXEL(scr, sx + x, sy + y));
1094     }
1095     else
1096     {
1097 	for(y = 0; y < h; y++)
1098 	{
1099 	    memcpy(pseudoImage + (ty + y) * REAL_SCREEN_SIZE_X + tx,
1100 		   scr->data   + (sy + y) * scr->width + sx,
1101 		   w);
1102 	}
1103     }
1104 
1105     if(isRealScreenChanged)
1106     {
1107 	/*???*/
1108 	x_sry_update();
1109     }
1110     updateClipX1 = tx;
1111     updateClipY1 = ty;
1112     updateClipX2 = x2;
1113     updateClipY2 = y2;
1114     isRealScreenChanged = 1;
1115 }
1116 
get_tmp_screen(int width_require,int height_require)1117 static VirtualScreen *get_tmp_screen(int width_require,
1118 				     int height_require)
1119 {
1120     if(tmpScreen == NULL)
1121     {
1122 	if(width_require < REAL_SCREEN_SIZE_X)
1123 	    width_require = REAL_SCREEN_SIZE_X;
1124 	if(height_require < REAL_SCREEN_SIZE_Y)
1125 	    height_require = REAL_SCREEN_SIZE_Y;
1126 	return tmpScreen = alloc_vscreen(width_require, height_require, 0);
1127     }
1128     if(tmpScreen->width * tmpScreen->height >= width_require * height_require)
1129     {
1130 	tmpScreen->width = width_require;
1131 	tmpScreen->height = height_require;
1132 	return tmpScreen;
1133     }
1134     if(tmpScreen)
1135 	free_vscreen(tmpScreen);
1136     return tmpScreen = alloc_vscreen(width_require, height_require, 0);
1137 }
1138 
normalize_rect(int * x1,int * y1,int * x2,int * y2)1139 static void normalize_rect(int *x1, int *y1, int *x2, int *y2)
1140 {
1141     int w, h, x0, y0;
1142 
1143     w = *x2 - *x1;
1144     if(w >= 0)
1145 	x0 = *x1;
1146     else
1147     {
1148 	w = -w;
1149 	x0 = *x2;
1150     }
1151 
1152     h = *y2 - *y1;
1153     if(h >= 0)
1154 	y0 = *y1;
1155     else
1156     {
1157 	h = -h;
1158 	y0 = *y2;
1159     }
1160 
1161     *x1 = x0;
1162     *y1 = y0;
1163     *x2 = x0 + w;
1164     *y2 = y0 + h;
1165 }
1166 
check_range(VirtualScreen * scr,int x1,int y1,int x2,int y2)1167 static int check_range(VirtualScreen *scr,
1168 		       int x1, int y1, int x2, int y2)
1169 {
1170     if(x1 < 0 ||
1171        y1 < 0 ||
1172        x2 >= scr->width ||
1173        y2 >= scr->height ||
1174        x1 > x2 ||
1175        y1 > y2)
1176     {
1177 	ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
1178 		  "Sherry WRD: Out of range: (%d,%d)-(%d,%d)"
1179 		  " > %dx%d, stop sherring",
1180 		  x1, y1, x2, y2, scr->width, scr->height);
1181 	err_to_stop = 1;
1182 	return 0;
1183     }
1184     return 1;
1185 }
1186 
virtual_screen(int scr)1187 static VirtualScreen *virtual_screen(int scr)
1188 {
1189     if(virtualScreen[scr] == NULL)
1190     {
1191 	ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
1192 		  "Sherry WRD: screen %d is not allocated, stop sherring",
1193 		  scr);
1194 	err_to_stop = 1;
1195 	return NULL;
1196     }
1197     return virtualScreen[scr];
1198 }
1199 
copy_vscreen_area(VirtualScreen * src,VirtualScreen * dest,int src_x1,int src_y1,int src_x2,int src_y2,int dest_x,int dest_y,int mask,int trans)1200 static void copy_vscreen_area(VirtualScreen *src,
1201 			      VirtualScreen *dest,
1202 			      int src_x1,
1203 			      int src_y1,
1204 			      int src_x2,
1205 			      int src_y2,
1206 			      int dest_x,
1207 			      int dest_y,
1208 			      int mask,
1209 			      int trans)
1210 {
1211     int x, y, sw, dw;
1212     uint8 *source, *target;
1213     int ww, hh;
1214 
1215     sw = src->width;
1216     dw = dest->width;
1217     source = src->data;
1218     target = dest->data;
1219     ww = src_x2 - src_x1 + 1;
1220     hh = src_y2 - src_y1 + 1;
1221 
1222     if(mask == 0xff && !trans)
1223     {
1224 	for(y = 0; y < hh; y++)
1225 	{
1226 	    memcpy(target + (dest_y + y) * dw + dest_x,
1227 		   source + (src_y1 + y) * sw + src_x1, ww);
1228 	}
1229     }
1230     else
1231     {
1232 	int p, q, i;
1233 	int skip_color;
1234 
1235 	skip_color = trans? src->transParent : -1;
1236 	for(y = 0; y < hh; y++)
1237 	{
1238 	    for(x = 0; x < ww; x++)
1239 	    {
1240 		p = source[(src_y1 + y) * sw + src_x1 + x];
1241 		if(p == skip_color)
1242 		    continue;
1243 		i = (dest_y + y) * dw + dest_x + x;
1244 		q = target[i];
1245 		target[i] = ROP3_CA0749(mask, p, q);
1246 	    }
1247 	}
1248     }
1249 }
1250 
sry_trans_partial(uint8 * data)1251 static void sry_trans_partial(uint8 *data)
1252 {
1253     VirtualScreen *src, *dest;
1254     int from, to;
1255     int x1, y1, x2, y2, tx, ty;
1256     int mask, trans;
1257 
1258     from = SRY_GET_SHORT(data + 0) & 0xffff;
1259     to   = SRY_GET_SHORT(data + 2) & 0xffff;
1260     mask = data[4];
1261     trans = data[5];
1262     x1   = SRY_GET_SHORT(data + 6) & 0xffff;
1263     y1   = SRY_GET_SHORT(data + 8) & 0xffff;
1264     x2   = SRY_GET_SHORT(data +10) & 0xffff;
1265     y2   = SRY_GET_SHORT(data +12) & 0xffff;
1266     tx   = SRY_GET_SHORT(data +14) & 0xffff;
1267     ty   = SRY_GET_SHORT(data +16) & 0xffff;
1268 
1269     if((src = virtual_screen(from)) == NULL)
1270 	return;
1271     if((dest = virtual_screen(to)) == NULL)
1272 	return;
1273 
1274 #ifdef SRY_DEBUG
1275     printf("Screen copy: %d:(%d,%d)-(%d,%d) -> %d:(%d,%d)  mask=0x%02x trans=%d\n",
1276 	   from, x1, y1, x2, y2, to, tx, ty,
1277 	   mask, trans);
1278 #endif /* SRY_DEBUG */
1279 
1280     normalize_rect(&x1, &y1, &x2, &y2);
1281     if(!check_range(src, x1, y1, x2, y2))
1282 	return;
1283     if(!check_range(dest, tx, ty, tx + x2 - x1, ty + y2 - y1))
1284 	return;
1285 
1286     if(src == dest)
1287     {
1288 	VirtualScreen *tmp;
1289 	tmp = get_tmp_screen(x2 + 1, y2 + 1);
1290 	tmp->transParent = src->transParent;
1291 	copy_vscreen_area(src, tmp, x1, y1, x2, y2, x1, y1, 0xff, 0);
1292 	src = tmp;
1293     }
1294 
1295     copy_vscreen_area(src, dest, x1, y1, x2, y2, tx, ty, mask, trans);
1296 }
1297 
sry_trans_partial_mask(uint8 * data)1298 static void sry_trans_partial_mask(uint8 *data)
1299 {
1300     int from, to;
1301     int planeMask, transparencyFlag;
1302     int x1, y1, x2, y2, toX, toY;
1303     int maskX, maskY;
1304     uint8 *maskData;
1305     VirtualScreen *src, *dest;
1306     int x, y, width, height;
1307     int mx, my;
1308     int bytesPerLine;
1309     int srcP, dstP;
1310 
1311     from = SRY_GET_SHORT(data + 0) & 0xffff;
1312     to = SRY_GET_SHORT(data + 2) & 0xffff;
1313     planeMask = data[4];
1314     transparencyFlag = data[5];
1315     x1 = SRY_GET_SHORT(data + 6) & 0xffff;
1316     y1 = SRY_GET_SHORT(data + 8) & 0xffff;
1317     x2 = SRY_GET_SHORT(data +10) & 0xffff;
1318     y2 = SRY_GET_SHORT(data +12) & 0xffff;
1319     toX = SRY_GET_SHORT(data +14) & 0xffff;
1320     toY = SRY_GET_SHORT(data +16) & 0xffff;
1321     maskX = data[18];
1322     maskY = data[19];
1323     maskData = data + 20;
1324 
1325     width = x2 - x1 + 1;
1326     height = y2 - y1 + 1;
1327 
1328     if((src = virtual_screen(from)) == NULL)
1329 	return;
1330     if((dest = virtual_screen(to)) == NULL)
1331 	return;
1332     normalize_rect(&x1, &y1, &x2, &y2);
1333     if(!check_range(src, x1, y1, x2, y2))
1334 	return;
1335     if(!check_range(dest, toX, toY, toX + x2 - x1, toY + y2 - y1))
1336 	return;
1337 
1338     if(src == dest)
1339     {
1340 	VirtualScreen *tmp;
1341 	tmp = get_tmp_screen(x2 + 1, y2 + 1);
1342 	tmp->transParent = src->transParent;
1343 	copy_vscreen_area(src, tmp, x1, y1, x2, y2, x1, y1, 0xff, 0);
1344 	src = tmp;
1345     }
1346 
1347     bytesPerLine = maskX;
1348     bytesPerLine = ((bytesPerLine + 7) & ~7); /* round up to 8 */
1349     bytesPerLine /= 8;
1350 
1351     my = y1 % maskY;
1352     for(y = 0; y < height; y++, my++)
1353     {
1354 	if(my == maskY)
1355 	    my = 0;
1356 	mx = x1 % maskX;
1357 	for(x = 0; x < width; x++, mx++)
1358 	{
1359 	    if(mx == maskX)
1360 		mx = 0;
1361 	    if(maskData[my * bytesPerLine + mx / 8] & (0x80 >> (mx%8)))
1362 	    {
1363 		srcP = VSCREEN_PIXEL(src, x1 + x, y1 + y);
1364 		if(!transparencyFlag || srcP != src->transParent)
1365 		{
1366 		    dstP = VSCREEN_PIXEL(dest, toX + x, toY + y);
1367 		    VSCREEN_PIXEL(dest, toX + x, toY + y) =
1368 			ROP3_CA0749(planeMask, srcP, dstP);
1369 		}
1370 	    }
1371 	}
1372     }
1373 }
1374 
1375 
sry_draw_box(uint8 * data)1376 static void sry_draw_box(uint8 *data)
1377 {
1378     int screen;
1379     int mask;
1380     int x1, y1, x2, y2, x, y;
1381     int color;
1382     VirtualScreen *v;
1383 
1384     screen = SRY_GET_SHORT(data + 0) & 0xffff;
1385     mask   = data[2];
1386     x1     = SRY_GET_SHORT(data + 3) & 0xffff;
1387     y1     = SRY_GET_SHORT(data + 5) & 0xffff;
1388     x2     = SRY_GET_SHORT(data + 7) & 0xffff;
1389     y2     = SRY_GET_SHORT(data + 9) & 0xffff;
1390     color  = data[11];
1391 
1392 #ifdef SRY_DEBUG
1393     printf("Box %d 0x%02x (%d,%d)-(%d,%d)\n", screen, mask, x1, y1, x2, y2);
1394 #endif /* SRY_DEBUG */
1395 
1396     if((v = virtual_screen(screen)) == NULL)
1397 	return;
1398     normalize_rect(&x1, &y1, &x2, &y2);
1399     if(!check_range(v, x1, y1, x2, y2))
1400 	return;
1401 
1402     if(mask == 0xff)
1403     {
1404 	for(y = y1; y <= y2; y++)
1405 	    memset(v->data + v->width * y + x1, color, x2 - x1 + 1);
1406     }
1407     else
1408     {
1409 	int p;
1410 	for(y = y1; y <= y2; y++)
1411 	    for(x = x1; x <= x2; x++)
1412 	    {
1413 		int i;
1414 		i = v->width * y + x;
1415 		p = v->data[i];
1416 		v->data[i] = ROP3_CA0749(mask, color, p);
1417 	    }
1418     }
1419 }
1420 
vscreen_drawline(VirtualScreen * scr,int x1,int y1,int x2,int y2,int pixel,int mask)1421 static void vscreen_drawline(VirtualScreen* scr,
1422 			     int x1, int y1, int x2, int y2,
1423 			     int pixel, int mask)
1424 {
1425     int dx, dy, incr1, incr2, d, x, y, xend, yend, xdirflag, ydirflag, idx;
1426 
1427     if(scr == NULL)
1428 	return;
1429 
1430     if(x1 < 0 ||
1431        y1 < 0 ||
1432        x2 >= scr->width ||
1433        y2 >= scr->height)
1434     {
1435 	ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
1436 		  "Sherry WRD: Out of range: (%d,%d)-(%d,%d)"
1437 		  " > %dx%d, stop sherring",
1438 		  x1, y1, x2, y2, scr->width, scr->height);
1439 	err_to_stop = 1;
1440 	return;
1441     }
1442 
1443     dx = x2 - x1; if(dx < 0) dx = -dx; /* dx = |x2-x1| */
1444     dy = y2 - y1; if(dy < 0) dy = -dy; /* dy = |y2-y1| */
1445 
1446     if(dy <= dx)
1447     {
1448 	d = 2 * dy - dx;
1449 	incr1 = 2 * dy;
1450 	incr2 = 2 * (dy - dx);
1451 	if(x1 > x2)
1452 	{
1453 	    x = x2;
1454 	    y = y2;
1455 	    ydirflag = -1;
1456 	    xend = x1;
1457 	}
1458 	else
1459 	{
1460 	    x = x1;
1461 	    y = y1;
1462 	    ydirflag = 1;
1463 	    xend = x2;
1464 	}
1465 
1466 	idx = scr->width * y + x;
1467 	scr->data[idx] = ROP3_CA0749(mask, pixel, scr->data[idx]);
1468 	if((y2 - y1) * ydirflag > 0)
1469 	{
1470 	    while(x < xend)
1471 	    {
1472 		x++;
1473 		if(d < 0)
1474 		    d += incr1;
1475 		else
1476 		{
1477 		    y++;
1478 		    d += incr2;
1479 		}
1480 		idx = scr->width * y + x;
1481 		scr->data[idx] = ROP3_CA0749(mask, pixel, scr->data[idx]);
1482 	    }
1483 	}
1484 	else
1485 	{
1486 	    while(x < xend)
1487 	    {
1488 		x++;
1489 		if(d < 0)
1490 		    d += incr1;
1491 		else
1492 		{
1493 		    y--;
1494 		    d += incr2;
1495 		}
1496 		idx = scr->width * y + x;
1497 		scr->data[idx] = ROP3_CA0749(mask, pixel, scr->data[idx]);
1498 	    }
1499 	}
1500     }
1501     else
1502     {
1503 	d = 2 * dx - dy;
1504 	incr1 = 2 * dx;
1505 	incr2 = 2 * (dx - dy);
1506 	if(y1 > y2)
1507 	{
1508 	    y = y2;
1509 	    x = x2;
1510 	    yend = y1;
1511 	    xdirflag = -1;
1512 	}
1513 	else
1514 	{
1515 	    y = y1;
1516 	    x = x1;
1517 	    yend = y2;
1518 	    xdirflag = 1;
1519 	}
1520 	idx = scr->width * y + x;
1521 	scr->data[idx] = ROP3_CA0749(mask, pixel, scr->data[idx]);
1522 	if((x2 - x1) * xdirflag > 0)
1523 	{
1524 	    while(y < yend)
1525 	    {
1526 		y++;
1527 		if(d <0)
1528 		    d += incr1;
1529 		else
1530 		{
1531 		    x++;
1532 		    d += incr2;
1533 		}
1534 		idx = scr->width * y + x;
1535 		scr->data[idx] = ROP3_CA0749(mask, pixel, scr->data[idx]);
1536 	    }
1537 	}
1538 	else
1539 	{
1540 	    while(y < yend)
1541 	    {
1542 		y++;
1543 		if(d < 0)
1544 		    d += incr1;
1545 		else
1546 		{
1547 		    x--;
1548 		    d += incr2;
1549 		}
1550 		idx = scr->width * y + x;
1551 		scr->data[idx] = ROP3_CA0749(mask, pixel, scr->data[idx]);
1552 	    }
1553 	}
1554     }
1555 }
1556 
sry_draw_vline(uint8 * data)1557 static void sry_draw_vline(uint8 *data)
1558 {
1559     int screen = SRY_GET_SHORT(data + 0) & 0xffff;
1560     int mask   = data[2];
1561     int x1     = SRY_GET_SHORT(data + 3) & 0xffff;
1562     int y1     = SRY_GET_SHORT(data + 5) & 0xffff;
1563     int y2     = SRY_GET_SHORT(data + 7) & 0xffff;
1564     int color  = data[9];
1565 
1566     vscreen_drawline(virtual_screen(screen),
1567 		     x1, y1, x1, y2, color, mask);
1568 }
1569 
sry_draw_hline(uint8 * data)1570 static void sry_draw_hline(uint8 *data)
1571 {
1572     int screen = SRY_GET_SHORT(data + 0) & 0xffff;
1573     int mask   = data[2];
1574     int x1     = SRY_GET_SHORT(data + 3) & 0xffff;
1575     int x2     = SRY_GET_SHORT(data + 5) & 0xffff;
1576     int y1     = SRY_GET_SHORT(data + 7) & 0xffff;
1577     int color  = data[9];
1578 
1579     vscreen_drawline(virtual_screen(screen),
1580 		     x1, y1, x2, y1, color, mask);
1581 }
1582 
sry_draw_line(uint8 * data)1583 static void sry_draw_line(uint8 *data)
1584 {
1585     int screen = SRY_GET_SHORT(data + 0) & 0xffff;
1586     int mask   = data[2];
1587     int x1     = SRY_GET_SHORT(data + 3) & 0xffff;
1588     int y1     = SRY_GET_SHORT(data + 5) & 0xffff;
1589     int x2     = SRY_GET_SHORT(data + 7) & 0xffff;
1590     int y2     = SRY_GET_SHORT(data + 9) & 0xffff;
1591     int color  = data[11];
1592 
1593     vscreen_drawline(virtual_screen(screen),
1594 		     x1, y1, x2, y2, color, mask);
1595 }
1596 
sry_pal_merge(uint8 * data)1597 static void sry_pal_merge(uint8 *data)
1598 {
1599     int Pal1, Pal2, PalResult;
1600     int Pal1in, Pal1bit, Pal1out;
1601     int Pal2in, Pal2bit, Pal2out;
1602     int Per1, Per2;
1603     int Pal1Mask, Pal2Mask, PalMask;
1604     int i;
1605     int i1, i2;
1606     SherryPaletteEntry *pal_in1, *pal_in2, *pal_res;
1607 
1608     Pal1 = SRY_GET_SHORT(data + 0) & 0xffff;
1609     Pal2 = SRY_GET_SHORT(data + 2) & 0xffff;
1610     PalResult = SRY_GET_SHORT(data + 4) & 0xffff;
1611     Pal1in = data[6];
1612     Pal1bit = data[7];
1613     Pal1out = data[8];
1614     Pal2in = data[9];
1615     Pal2bit = data[10];
1616     Pal2out = data[11];
1617     Per1 = data[12];
1618     Per2 = data[13];
1619 
1620     Pal1Mask = 0xff >> ( 8 - Pal1bit );
1621     Pal1Mask <<= Pal1out;
1622     Pal2Mask = 0xff >> ( 8 - Pal2bit );
1623     Pal2Mask <<= Pal2out;
1624     PalMask  = Pal1Mask | Pal2Mask;
1625 
1626 #ifdef SRY_DEBUG
1627     printf("palette merge %d(%d%%) %d(%d%%) => %d (mask=0x%x)\n",
1628 	   Pal1, Per1,
1629 	   Pal2, Per2,
1630 	   PalResult,
1631 	   PalMask);
1632 #endif /* SRY_DEBUG */
1633 
1634     if(virtualPalette[Pal1] == NULL)
1635     {
1636 	ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
1637 		  "Sherry WRD: palette %d is not allocated, stop sherring",
1638 		  Pal1);
1639 	err_to_stop = 1;
1640 	return;
1641     }
1642 
1643     if(virtualPalette[Pal2] == NULL)
1644     {
1645 	ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
1646 		  "Sherry WRD: palette %d is not allocated, stop sherring",
1647 		  Pal2);
1648 	err_to_stop = 1;
1649 	return;
1650     }
1651 
1652     if(virtualPalette[PalResult] == NULL)
1653     {
1654 	ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
1655 		  "Sherry WRD: palette %d is not allocated, stop sherring",
1656 		  PalResult);
1657 	err_to_stop = 1;
1658 	return;
1659     }
1660 
1661     pal_in1 = virtualPalette[Pal1]->entry;
1662     pal_in2 = virtualPalette[Pal2]->entry;
1663     pal_res = virtualPalette[PalResult]->entry;
1664 
1665     for(i = 0; i < MAX_COLORS; i++)
1666     {
1667 	if((i & PalMask) == i)
1668 	{
1669 	    int p;
1670 
1671 	    i1 = (i & Pal1Mask) >> Pal1in;
1672 	    i2 = (i & Pal2Mask) >> Pal2in;
1673 
1674 	    p = pal_in1[i1].r * Per1 / 100 + pal_in2[i2].r * Per2 / 100;
1675 	    if(p > 0xff) p = 0xff;
1676 	    pal_res[i].r = p;
1677 
1678 	    p = pal_in1[i1].g * Per1 / 100 + pal_in2[i2].g * Per2 / 100;
1679 	    if(p > 0xff) p = 0xff;
1680 	    pal_res[i].g = p;
1681 
1682 	    p = pal_in1[i1].b * Per1 / 100 + pal_in2[i2].b * Per2 / 100;
1683 	    if(p > 0xff) p = 0xff;
1684 	    pal_res[i].b = p;
1685 	}
1686     }
1687 }
1688 
sry_pal_copy(uint8 * data)1689 static void sry_pal_copy(uint8 *data)
1690 {
1691     int pal1, pal2;
1692 
1693     pal1 = SRY_GET_SHORT(data + 0) & 0xffff;
1694     pal2 = SRY_GET_SHORT(data + 2) & 0xffff;
1695 
1696 #ifdef SRY_DEBUG
1697     printf("Copy palette %d->%d\n", pal1, pal2);
1698 #endif /* SRY_DEBUG */
1699 
1700     if(virtualPalette[pal1] == NULL)
1701     {
1702 	ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
1703 		  "Sherry WRD: palette %d is not allocated, stop sherring",
1704 		  pal1);
1705 	err_to_stop = 1;
1706 	return;
1707     }
1708 
1709     if(virtualPalette[pal2] == NULL)
1710 	virtualPalette[pal2] =
1711 	    (SherryPalette *)safe_malloc(sizeof(SherryPalette));
1712     memcpy(virtualPalette[pal2], virtualPalette[pal1], sizeof(SherryPalette));
1713 }
1714 
sry_text(uint8 * data)1715 static void sry_text(uint8 *data)
1716 {
1717     int screen, mask, mode, bg, fg, tx, ty;
1718     char *str;
1719     int len, advance;
1720     VirtualScreen *scr;
1721 
1722     screen = SRY_GET_SHORT(data + 0);
1723     mask = data[2];
1724     mode = data[3];
1725     fg   = data[4];
1726     bg   = data[5];
1727     tx    = SRY_GET_SHORT(data + 6);
1728     ty    = SRY_GET_SHORT(data + 8);
1729     str  = (char *)data + 10;
1730     len  = strlen(str);
1731 
1732     if(len == 0)
1733 	return;
1734 
1735 #ifdef SRY_DEBUG
1736     printf("%d 0x%02x %d %d %d (%d,%d)\n%s\n",
1737 	   screen, mask, mode, fg, bg, tx, ty, str);
1738 #endif /* SRY_DEBUG */
1739 
1740     if((scr = virtual_screen(screen)) == NULL)
1741 	return;
1742 
1743     if(!check_range(scr,
1744 		    tx, ty, tx + CHAR_WIDTH1 * len - 1, ty + CHAR_HEIGHT - 1))
1745 	return;
1746 
1747     while((advance = bitmap_drawimage(imageBitmap, str, len)) > 0)
1748     {
1749 	int width, bx, by, p;
1750 	width = advance * CHAR_WIDTH1;
1751 
1752 	for(by = 0; by < CHAR_HEIGHT; by++)
1753 	{
1754 	    for(bx = 0; bx < width; bx++)
1755 	    {
1756 		if(XGetPixel(imageBitmap->im, bx, by))
1757 		{
1758 		    if(mode & 1)
1759 		    {
1760 			p = VSCREEN_PIXEL(scr, tx + bx, ty + by);
1761 			VSCREEN_PIXEL(scr, tx + bx, ty + by) =
1762 			    ROP3_CA0749(mask, fg, p);
1763 		    }
1764 		}
1765 		else
1766 		{
1767 		    if(mode & 2)
1768 		    {
1769 			p = VSCREEN_PIXEL(scr, tx + bx, ty + by);
1770 			VSCREEN_PIXEL(scr, tx + bx, ty + by) =
1771 			    ROP3_CA0749(mask, bg, p);
1772 		    }
1773 		}
1774 	    }
1775 	}
1776 
1777 	str += advance;
1778 	len -= advance;
1779 	tx  += advance * CHAR_WIDTH1;
1780     }
1781 }
1782 
x_sry_clear(void)1783 void x_sry_clear(void)
1784 {
1785     int i;
1786 
1787     if(theDisplay == NULL)
1788 	return;
1789 
1790     isRealPaletteChanged = 0;
1791     isRealScreenChanged = 0;
1792     err_to_stop = 0;
1793 
1794     init_palette();
1795 
1796     XSetWindowBackground(theDisplay, theWindow, basePixel);
1797     XClearWindow(theDisplay, theWindow);
1798 
1799     clear_image_pixmap(theRealScreen, basePixel);
1800 
1801     for(i = 0; i < MAX_VIRTUAL_SCREENS; i++)
1802 	if(virtualScreen[i] != NULL)
1803 	{
1804 	    free_vscreen(virtualScreen[i]);
1805 	    virtualScreen[i] = NULL;
1806 	}
1807     if(tmpScreen)
1808     {
1809 	free(tmpScreen);
1810 	tmpScreen = NULL;
1811     }
1812 
1813     for(i = 0; i < MAX_VIRTUAL_PALETTES; i++)
1814 	if(virtualPalette[i] != NULL)
1815 	{
1816 	    free(virtualPalette[i]);
1817 	    virtualPalette[i] = NULL;
1818 	}
1819     memset(realPalette, 0, sizeof(realPalette));
1820     if(theClass == TrueColor)
1821 	memset(pseudoImage, 0, REAL_SCREEN_SIZE_X * REAL_SCREEN_SIZE_Y);
1822 }
1823 
1824 
1825 #ifdef SRY_DEBUG
print_command(uint8 * data,int len)1826 static void print_command(uint8 *data, int len)
1827 {
1828     int i;
1829     printf("sherry:");
1830     for(i = 0; i < len; i++)
1831     {
1832 	printf(" 0x%02x", data[i]);
1833 	if(i >= 28)
1834 	{
1835 	    printf("...");
1836 	    break;
1837 	}
1838     }
1839     printf("\n");
1840     fflush(stdout);
1841 }
1842 #endif /* SRY_DEBUG */
1843 
x_sry_wrdt_apply(uint8 * data,int len)1844 void x_sry_wrdt_apply(uint8 *data, int len)
1845 {
1846     int op, skip_bit;
1847 
1848     if(err_to_stop || theDisplay == NULL)
1849 	return;
1850 
1851 #ifdef SRY_DEBUG
1852     print_command(data, len);
1853 #endif /* SRY_DEBUG */
1854 
1855     op = *data++;
1856     len--;
1857 
1858     skip_bit = op & 0x80;
1859     if(skip_bit && aq_filled_ratio() < 0.2)
1860 	return;
1861     op &= 0x7F;
1862 
1863     switch(op)
1864     {
1865       case 0x00: /* DataEnd */
1866 	break;
1867       case 0x01:
1868 	ctl->cmsg(CMSG_INFO, VERB_DEBUG, "sherry start");
1869 	wrd_init_path();
1870 	x_sry_clear();
1871 	break;
1872       case 0x21:
1873 	ctl->cmsg(CMSG_INFO, VERB_DEBUG, "new pal 0x21");
1874 	sry_new_vpal(data, len);
1875 	break;
1876       case 0x22:
1877 	ctl->cmsg(CMSG_INFO, VERB_DEBUG, "free pal 0x22");
1878 	sry_free_vpal(data, len);
1879 	break;
1880       case 0x25:
1881 	ctl->cmsg(CMSG_INFO, VERB_DEBUG, "new vram 0x25");
1882 	sry_new_vram(data, len);
1883 	break;
1884       case 0x26:
1885 	ctl->cmsg(CMSG_INFO, VERB_DEBUG, "free vram 0x26");
1886 	sry_free_vram(data, len);
1887 	break;
1888       case 0x27:
1889 	ctl->cmsg(CMSG_INFO, VERB_DEBUG, "load PNG 0x27");
1890 	sry_load_png(data);
1891 	break;
1892       case 0x31:
1893 	ctl->cmsg(CMSG_INFO, VERB_DEBUG,
1894 		  "palette trans 0x31 (%d)", SRY_GET_SHORT(data));
1895 	sry_pal_v2r(data);
1896 	break;
1897       case 0x35:
1898 	ctl->cmsg(CMSG_INFO, VERB_DEBUG,
1899 		  "image copy 0x35 (%d)", SRY_GET_SHORT(data));
1900 	sry_trans_all(data);
1901 	break;
1902       case 0x36:
1903 	ctl->cmsg(CMSG_INFO, VERB_DEBUG,
1904 		  "image copy 0x36 (%d)", SRY_GET_SHORT(data));
1905 	sry_trans_partial_real(data);
1906 	break;
1907       case 0x41:
1908 	ctl->cmsg(CMSG_INFO, VERB_DEBUG, "set pal 0x41");
1909 	sry_pal_set(data, len);
1910 	break;
1911       case 0x42:
1912 	ctl->cmsg(CMSG_INFO, VERB_DEBUG, "pal merge 0x42");
1913 	sry_pal_merge(data);
1914 	break;
1915       case 0x43:
1916 	ctl->cmsg(CMSG_INFO, VERB_DEBUG, "pal copy 0x43");
1917 	sry_pal_copy(data);
1918 	break;
1919       case 0x51:
1920 	ctl->cmsg(CMSG_INFO, VERB_DEBUG, "text 0x51");
1921 	sry_text(data);
1922 	break;
1923       case 0x52:
1924 	ctl->cmsg(CMSG_INFO, VERB_DEBUG, "draw box 0x52");
1925 	sry_draw_box(data);
1926 	break;
1927       case 0x53:
1928 	ctl->cmsg(CMSG_INFO, VERB_DEBUG, "draw line 0x53");
1929 	sry_draw_vline(data);
1930 	break;
1931       case 0x54:
1932 	ctl->cmsg(CMSG_INFO, VERB_DEBUG, "draw line 0x54");
1933 	sry_draw_hline(data);
1934 	break;
1935       case 0x55:
1936 	ctl->cmsg(CMSG_INFO, VERB_DEBUG, "draw line 0x55");
1937 	sry_draw_line(data);
1938 	break;
1939       case 0x61:
1940 	ctl->cmsg(CMSG_INFO, VERB_DEBUG, "image copy 0x61");
1941 	sry_trans_partial(data);
1942 	break;
1943       case 0x62:
1944 	ctl->cmsg(CMSG_INFO, VERB_DEBUG, "image copy 0x62");
1945 	sry_trans_partial_mask(data);
1946 	break;
1947       case 0x10:
1948       case 0x11:
1949       case 0x12:
1950       case 0x13:
1951       case 0x14:
1952       case 0x15:
1953       case 0x16:
1954       case 0x17:
1955       case 0x18:
1956       case 0x19:
1957       case 0x1a:
1958       case 0x1b:
1959       case 0x1c:
1960       case 0x1d:
1961       case 0x1e:
1962       case 0x1f:
1963       case 0x20:
1964       case 0x71:
1965       case 0x72:
1966       case 0x7f:
1967 	ctl->cmsg(CMSG_WARNING, VERB_DEBUG,
1968 		  "Sherry WRD 0x%x: not supported, ignore", op);
1969 	break;
1970 
1971       default:
1972 	ctl->cmsg(CMSG_ERROR, VERB_NORMAL,
1973 		  "Sherry WRD 0x%x: not defined, stop sherring", op);
1974 	err_to_stop = 1;
1975 	break;
1976     }
1977 }
1978 
x_sry_redraw_ctl(int flag)1979 void x_sry_redraw_ctl(int flag)
1980 {
1981     draw_ctl_flag = flag;
1982     if(draw_ctl_flag)
1983 	update_real_screen(0, 0, REAL_SCREEN_SIZE_X, REAL_SCREEN_SIZE_Y);
1984 }
1985 
x_sry_update(void)1986 void x_sry_update(void)
1987 {
1988     if(err_to_stop)
1989 	return;
1990 
1991 #ifdef SRY_DEBUG
1992     puts("Update pallete & screen");
1993 #endif /* SRY_DEBUG */
1994 
1995     if(!isRealPaletteChanged && !isRealScreenChanged)
1996 	return;
1997     if(isRealPaletteChanged)
1998 	updatePalette();
1999     if(isRealScreenChanged)
2000 	updateScreen(updateClipX1, updateClipY1,
2001 		     updateClipX2 - updateClipX1 + 1,
2002 		     updateClipY2 - updateClipY1 + 1);
2003     XSync(theDisplay, False);
2004 }
2005 
2006 
2007 /**** ImagePixmap interfaces ****/
create_image_pixmap(int width,int height,int depth)2008 static ImagePixmap *create_image_pixmap(int width, int height, int depth)
2009 {
2010     ImagePixmap *ip;
2011 
2012     ip = (ImagePixmap *)safe_malloc(sizeof(ImagePixmap));
2013     ip->pm = XCreatePixmap(theDisplay, theWindow, width, height, depth);
2014     ip->im = XGetImage(theDisplay, ip->pm, 0, 0, width, height,
2015 		       AllPlanes, ZPixmap);
2016     ip->gc = createGC(theDisplay, ip->pm);
2017     ip->depth = depth;
2018 #if XSHM_SUPPORT
2019     ip->shminfo.shmid = -1;
2020 #endif
2021 
2022     return ip;
2023 }
2024 
2025 #if XSHM_SUPPORT
2026 static int shm_error;
my_err_handler(Display * dpy,XErrorEvent * e)2027 static int my_err_handler(Display* dpy, XErrorEvent* e)
2028 {
2029     shm_error = e->error_code;
2030     ctl->cmsg(CMSG_WARNING, VERB_VERBOSE,
2031 	      "Warning: X Sherry Warning: Can't create SHM Pixmap. error-code=%d",
2032 	      shm_error);
2033     return shm_error;
2034 }
create_shm_image_pixmap(int width,int height,int depth)2035 static ImagePixmap *create_shm_image_pixmap(int width, int height, int depth)
2036 {
2037     XErrorHandler origh;
2038     ImagePixmap *ip;
2039     int shm_depth;
2040 
2041     shm_depth = depth;
2042     ip = (ImagePixmap *)safe_malloc(sizeof(ImagePixmap));
2043 
2044     shm_error = 0;
2045     origh = XSetErrorHandler(my_err_handler);
2046 
2047     /* There is no need to initialize XShmSegmentInfo structure
2048      * before the call to XShmCreateImage.
2049      */
2050     ip->im = XShmCreateImage(theDisplay, theVisual, shm_depth,
2051 			     ZPixmap, NULL,
2052 			     &ip->shminfo, width, height);
2053     if(ip->im == NULL)
2054     {
2055 	if(shm_error == 0)
2056 	    shm_error = -1;
2057 	goto done;
2058     }
2059 
2060     /* The next step is to create the shared memory segment.
2061      * The return value of shmat() should be stored both
2062      * the XImage structure and the shminfo structure.
2063      */
2064     ip->shminfo.shmid = shmget(IPC_PRIVATE,
2065 			       ip->im->bytes_per_line * ip->im->height,
2066 			       IPC_CREAT | 0777);
2067     if(ip->shminfo.shmid == -1)
2068     {
2069 	ctl->cmsg(CMSG_WARNING, VERB_VERBOSE,
2070 		  "X Sherry Warning: Can't create SHM Pixmap.\n"
2071 		  "shmget: %s", strerror(errno));
2072 	XDestroyImage(ip->im);
2073 	ip->im = NULL;
2074 	shm_error = -1;
2075 	goto done;
2076     }
2077     ip->shminfo.shmaddr = ip->im->data =
2078 	(char *)shmat(ip->shminfo.shmid, NULL, 0);
2079     if(ip->shminfo.shmaddr == (void *)-1)
2080     {
2081 	ctl->cmsg(CMSG_WARNING, VERB_VERBOSE,
2082 		  "X Sherry Warning: Can't create SHM Pixmap.\n"
2083 		  "shmget: %s", strerror(errno));
2084 	shmctl(ip->shminfo.shmid, IPC_RMID, NULL);
2085 	XDestroyImage(ip->im);
2086 	ip->im = NULL;
2087 	shm_error = -1;
2088 	goto done;
2089     }
2090 
2091 
2092     /* If readOnly is True, XShmGetImage calls will fail. */
2093     ip->shminfo.readOnly = False;
2094 
2095 
2096     /* Tell the server to attach to your shared memory segment. */
2097     if(XShmAttach(theDisplay, &ip->shminfo) == 0)
2098     {
2099 	if(shm_error == 0)
2100 	{
2101 	    ctl->cmsg(CMSG_WARNING, VERB_VERBOSE,
2102 		      "X Sherry Warning: Can't create SHM Pixmap.\n"
2103 		      "Can't attach to the shared memory segment.");
2104 	    shm_error = -1;
2105 	}
2106 	shmdt(ip->shminfo.shmaddr);
2107 	shmctl(ip->shminfo.shmid, IPC_RMID, NULL);
2108 	XDestroyImage(ip->im);
2109 	ip->im = NULL;
2110 	goto done;
2111     }
2112 
2113     XSync(theDisplay, False);		/* Wait until ready. */
2114 
2115     ip->pm = XShmCreatePixmap(theDisplay, theWindow, ip->im->data,
2116 			      &ip->shminfo, width, height, shm_depth);
2117     if(ip->pm == None)
2118     {
2119 	if(shm_error == 0)
2120 	{
2121 	    ctl->cmsg(CMSG_WARNING, VERB_VERBOSE,
2122 		      "X Sherry Warning: Can't create SHM Pixmap.\n"
2123 		      "XShmCreatePixmap() is failed");
2124 	    shm_error = -1;
2125 	}
2126 	shmdt(ip->shminfo.shmaddr);
2127 	shmctl(ip->shminfo.shmid, IPC_RMID, NULL);
2128 	XDestroyImage(ip->im);
2129 	ip->im = NULL;
2130 	goto done;
2131     }
2132 
2133   done:
2134     XSetErrorHandler(origh);
2135 
2136     if(ip->im != NULL)
2137     {
2138 	ip->gc = createGC(theDisplay, ip->pm);
2139 	ip->depth = shm_depth;
2140     }
2141     else
2142     {
2143 	free(ip);
2144 	ip = create_image_pixmap(width, height, depth);
2145     }
2146     return ip;
2147 }
2148 #endif
2149 
clear_image_pixmap(ImagePixmap * ip,unsigned long pixel)2150 static void clear_image_pixmap(ImagePixmap *ip, unsigned long pixel)
2151 {
2152     int x, y, w, h;
2153 
2154     w = ip->im->width;
2155     h = ip->im->height;
2156 
2157     XSetForeground(theDisplay, ip->gc, pixel);
2158     XFillRectangle(theDisplay, ip->pm, ip->gc,
2159 		   0, 0, ip->im->width, ip->im->height);
2160 #if XSHM_SUPPORT
2161     if(ip->shminfo.shmid != -1)
2162 	return;
2163 #endif /* XSHM_SUPPORT */
2164     for(y = 0; y < h; y++)
2165 	for(x = 0; x < w; x++){
2166 	    XPutPixel(ip->im, x, y, pixel);
2167 	}
2168 }
2169 
free_image_pixmap(ImagePixmap * ip)2170 static void free_image_pixmap(ImagePixmap *ip)
2171 {
2172     XFreePixmap(theDisplay, ip->pm);
2173 
2174 #if XSHM_SUPPORT
2175     if(ip->shminfo.shmid != -1)
2176     {
2177 	/* To destory a shard memory XImage, you should call XShmDetach()
2178 	 * first.
2179 	 */
2180 	XShmDetach(theDisplay, &ip->shminfo);
2181 
2182 	/* Unmap shared memory segment */
2183 	shmdt(ip->shminfo.shmaddr);
2184 
2185 	/* Remove a shared memory ID from the system */
2186 	shmctl(ip->shminfo.shmid, IPC_RMID, NULL);
2187     }
2188 #endif /* XSHM_SUPPORT */
2189     XDestroyImage(ip->im);
2190     free(ip);
2191 }
2192 
2193 
2194 #define IS_MULTI_BYTE(c) (((c)&0x80) && \
2195 			  ((0x1 <= ((c)&0x7F) && ((c)&0x7F) <= 0x1f) || \
2196 			   (0x60 <= ((c)&0x7F) && ((c)&0x7F) <= 0x7c)))
2197 
2198 /* bitmap_drawimage() Draws string into image
2199  * It returns number of bytes drawn
2200  */
bitmap_drawimage(ImagePixmap * ip,char * sjis_str,int nbytes)2201 static int bitmap_drawimage(ImagePixmap *ip, char *sjis_str, int nbytes)
2202 {
2203     int write_len;
2204     int sjis_c1, sjis_c2;
2205     int x, width, height;
2206 
2207     x = write_len = 0;
2208     while(*sjis_str && write_len < IMAGEBITMAPLEN)
2209     {
2210 	sjis_c1 = *sjis_str & 0xff;
2211 	sjis_str++;
2212 
2213 	if(IS_MULTI_BYTE(sjis_c1))
2214 	{
2215 	    int e1, e2;
2216 	    XChar2b b;
2217 
2218 	    if(write_len+1 == IMAGEBITMAPLEN)
2219 		break;
2220 	    sjis_c2 = *sjis_str & 0xff;
2221 	    if(sjis_c2 == 0)
2222 		break;
2223 	    sjis_str++;
2224 
2225 	    /* SJIS to EUC */
2226 	    if(sjis_c2 >= 0x9f)
2227 	    {
2228 		if(sjis_c1 >= 0xe0)
2229 		    e1 = sjis_c1 * 2 - 0xe0;
2230 		else
2231 		    e1 = sjis_c1 * 2 - 0x60;
2232 		e2 = sjis_c2 + 2;
2233 	    }
2234 	    else
2235 	    {
2236 		if(sjis_c1 >= 0xe0)
2237 		    e1 = sjis_c1 * 2 - 0xe1;
2238 		else
2239 		    e1 = sjis_c1 * 2 - 0x61;
2240 		if(sjis_c2 >= 0x7f)
2241 		    e2 = sjis_c2 + 0x60;
2242 		else
2243 		    e2 = sjis_c2 +  0x61;
2244 	    }
2245 
2246 	    b.byte1 = e1 & 0x7f;
2247 	    b.byte2 = e2 & 0x7f;
2248 	    XSetFont(theDisplay, ip->gc, theFont16->fid);
2249 	    XDrawImageString16(theDisplay, ip->pm, ip->gc,
2250 			       x - lbearing16, ascent16, &b, 1);
2251 	    x += CHAR_WIDTH2;
2252 	    write_len += 2;
2253 	}
2254 	else
2255 	{
2256 	    char c = sjis_c1;
2257 	    XSetFont(theDisplay, ip->gc, theFont8->fid);
2258 	    XDrawImageString(theDisplay, ip->pm, ip->gc,
2259 			     x - lbearing8, ascent8, &c, 1);
2260 	    x += CHAR_WIDTH1;
2261 	    write_len++;
2262 	}
2263     }
2264 
2265     if(write_len == 0)
2266 	return 0; /* Terminate repeating call */
2267 
2268 #if XSHM_SUPPORT
2269     if(ip->shminfo.shmid != -1)
2270     {
2271         XSync(theDisplay, 0); /* Wait until ready */
2272 	return write_len;
2273     }
2274 #endif /* XSHM_SUPPORT */
2275 
2276     /* XSHM is not supported.
2277      * Now, re-allocate XImage structure from the pixmap.
2278      */
2279     width = ip->im->width;
2280     height = ip->im->height;
2281     XDestroyImage(ip->im);
2282     ip->im = XGetImage(theDisplay, ip->pm, 0, 0, width, height,
2283 		       AllPlanes, ZPixmap);
2284 
2285     return write_len;
2286 }
2287 
2288 
2289 /**** VirtualScreen intarfaces ****/
alloc_vscreen(int width,int height,int transParent)2290 static VirtualScreen *alloc_vscreen(int width, int height, int transParent)
2291 {
2292     VirtualScreen *scr;
2293     int size = width * height;
2294 
2295     /* Shared the allocated memory for data and the structure */
2296     scr = (VirtualScreen *)safe_malloc(sizeof(VirtualScreen) + size);
2297     scr->width = width;
2298     scr->height = height;
2299     scr->transParent = transParent;
2300     memset(scr->data, transParent, size);
2301     return scr;
2302 }
2303 
free_vscreen(VirtualScreen * scr)2304 static void free_vscreen(VirtualScreen *scr)
2305 {
2306     free(scr);
2307 }
2308 
x_sry_event(void)2309 void x_sry_event(void)
2310 {
2311     if(QLength(theDisplay) == 0)
2312 	XSync(theDisplay, False);
2313     while(QLength(theDisplay) > 0)
2314     {
2315 	XEvent e;
2316 	XNextEvent(theDisplay, &e);
2317 	switch(e.type)
2318 	{
2319 	  case Expose:
2320 	    update_real_screen(e.xexpose.x, e.xexpose.y,
2321 			       e.xexpose.width, e.xexpose.height);
2322 	    break;
2323 	}
2324 	if(QLength(theDisplay) == 0)
2325 	    XSync(theDisplay, False);
2326     }
2327 }
2328 #endif /* ENABLE_SHERRY */
2329