1 /* ---------------------------------------------------------------------- *
2  * lcx11.c
3  * This file is part of lincity.
4  * Lincity is copyright (c) I J Peters 1995-1997, (c) Greg Sharp 1997-2001.
5  * ---------------------------------------------------------------------- */
6 #include "lcconfig.h"
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <assert.h>
10 #include <math.h>
11 #include "lcstring.h"
12 #include "lcintl.h"
13 #include "fileutil.h"
14 #include "lclib.h"
15 
16 #include <X11/Xlib.h>
17 #include <X11/Xatom.h>
18 #include <X11/Xutil.h>
19 #include <X11/keysym.h>
20 #include <X11/keysymdef.h>
21 #include "lin-city.h"
22 #include "lctypes.h"
23 #include "cliglobs.h"
24 #include "lcx11.h"
25 #include "pixmap.h"
26 #include "mouse.h"
27 #include "screen.h"
28 
29 #ifndef M_PI
30 #define M_PI            3.14159265358979323846
31 #endif
32 
33 #define USE_IMAGES 1
34 
35 #define DEBUG_X11_MOUSE
36 #undef DEBUG_X11_MOUSE
37 
38 void
set_pointer_confinement(void)39 set_pointer_confinement (void)
40 {
41     if (confine_flag) {
42 	XGrabPointer (display.dpy, display.win, 0,
43 		      ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
44 		      GrabModeAsync, GrabModeAsync,
45 		      display.win, None, CurrentTime);
46     } else {
47 	XUngrabPointer (display.dpy, CurrentTime);
48     }
49 }
50 
51 int
confine_pointer(int x,int y,int w,int h)52 confine_pointer (int x, int y, int w, int h)
53 {
54 
55     if (display.pointer_confined)
56 	return 0;
57 
58     display.confinewin =
59 	XCreateSimpleWindow(display.dpy, display.win,
60 			    10, 10, w, h,
61 			    0, 0, 0);
62 
63     XMapWindow(display.dpy, display.confinewin);
64 
65     XGrabPointer(display.dpy, display.root, 1,
66 		 ButtonPressMask | ButtonReleaseMask | PointerMotionMask,
67 		 GrabModeAsync, GrabModeAsync, display.confinewin,
68 		 None, CurrentTime);
69 
70 
71     display.pointer_confined = 1;
72     return 1;
73 
74 }
75 
76 
77 void
unconfine_pointer(void)78 unconfine_pointer (void)
79 {
80     XUngrabPointer(display.dpy, CurrentTime);
81     XDestroyWindow(display.dpy, display.confinewin);
82     display.pointer_confined = 0;
83 }
84 
85 void
setcustompalette(void)86 setcustompalette (void)
87 {
88   char s[100];
89   int n, r, g, b, i, flag[256];
90   XColor pal[256];
91   FILE *inf;
92   for (i = 0; i < 256; i++)
93     flag[i] = 0;
94   if ((inf = fopen (colour_pal_file, "r")) == 0)
95     HandleError ("Can't find the colour pallet file", FATAL);
96 
97   while (feof (inf) == 0)
98     {
99       fgets (s, 99, inf);
100       if (sscanf (s, "%d %d %d %d", &n, &r, &g, &b) == 4)
101 	{
102 	  pal[n].red = r;
103 	  pal[n].green = g;
104 	  pal[n].blue = b;
105 	  pal[n].flags = DoRed | DoGreen | DoBlue;
106 	  pal[n].pixel = colour_table[n];	/* ??? */
107 
108 	  flag[n] = 1;
109 	}
110     }
111   fclose (inf);
112   for (i = 0; i < 256; i++)
113     {
114       if (flag[i] == 0)
115 	{
116 	  printf ("Colour %d not loaded\n", i);
117 	  HandleError ("Can't continue", FATAL);
118 	}
119       pal[i].red = (unsigned char) ((pal[i].red
120 		  * (1 - gamma_correct_red)) + (64 * sin ((float) pal[i].red
121 					* M_PI / 128)) * gamma_correct_red);
122 
123       pal[i].green = (unsigned char) ((pal[i].green
124 	      * (1 - gamma_correct_green)) + (64 * sin ((float) pal[i].green
125 				      * M_PI / 128)) * gamma_correct_green);
126 
127       pal[i].blue = (unsigned char) ((pal[i].blue
128 		* (1 - gamma_correct_blue)) + (64 * sin ((float) pal[i].blue
129 				       * M_PI / 128)) * gamma_correct_blue);
130     }
131 
132   do_setcustompalette (pal);
133 }
134 
135 void
open_setcustompalette(XColor * inpal)136 open_setcustompalette (XColor * inpal)
137 {
138     do_setcustompalette (inpal);
139 }
140 
141 void
do_setcustompalette(XColor * inpal)142 do_setcustompalette (XColor * inpal)
143 {
144   int i, n, me = 0, flag[256], vid;
145   int depth;
146   long unsigned int plane_masks[3];
147   XColor pal[256];
148   int writeable_p;
149 
150   display.cmap = XDefaultColormap (display.dpy, display.screen);
151   depth = DefaultDepth (display.dpy, display.screen);
152 
153   /* Decide, if the colormap is writable */
154   {
155     Visual *visual = DefaultVisual (display.dpy, display.screen);
156 #if defined(__cplusplus) || defined(c_plusplus)
157     int visual_class = visual->c_class;
158 #else
159     int visual_class = visual->class;
160 #endif
161     writeable_p = (visual_class == PseudoColor || visual_class == GrayScale);
162   }
163 
164   if (writeable_p)
165     {
166       if (XAllocColorCells (display.dpy, display.cmap, 0
167 			    ,plane_masks, 0, colour_table, 256) == 0)
168 	{
169 	  me = (*DefaultVisual (display.dpy, display.screen)).map_entries;
170 	  vid = (*DefaultVisual (display.dpy, display.screen)).visualid;
171 	  display.cmap = XCreateColormap (display.dpy, display.win
172 				,DefaultVisual (display.dpy, display.screen)
173 	  /*      ,PseudoColor */
174 					  ,AllocNone);
175 	  if (me == 256 && depth != 24)
176 	    {
177 	      if (XAllocColorCells (display.dpy, display.cmap, 0
178 				    ,plane_masks, 0, colour_table, 256) != 0) {
179 		  /* printf ("Allocated 256 cells\n"); */
180 	      }
181 	      else {
182 		  printf ("Couldn't allocate 256 cells\n");
183 	      }
184 	    }
185 	  else
186 	    for (i = 0; i < 256; i++)
187 	      colour_table[i] = i;
188 	}
189       if (!display.cmap)
190 	HandleError ("No default colour map", FATAL);
191     }
192 
193   for (i = 0; i < 256; i++)
194     flag[i] = 0;
195 
196   for (n = 0; n < 256; n++)
197     {
198       pal[n].red = inpal[n].red << 10;
199       pal[n].green = inpal[n].green << 10;
200       pal[n].blue = inpal[n].blue << 10;
201       pal[n].flags = DoRed | DoGreen | DoBlue;
202       if (writeable_p)
203 	pal[n].pixel = colour_table[n];
204       else
205 	{
206 	  if (XAllocColor (display.dpy
207 			   ,display.cmap, &(pal[n])) == 0)
208 	    HandleError ("alloc colour failed"
209 			 ,FATAL);
210 	  colour_table[n] = pal[n].pixel;
211 	  XSetForeground (display.dpy
212 			  ,display.pixcolour_gc[n]
213 			  ,colour_table[n]);
214 	}
215       flag[n] = 1;
216     }
217 
218   if (writeable_p)
219     {
220       XStoreColors (display.dpy, display.cmap, pal, 256);
221       XFlush (display.dpy);
222     }
223   XSetWindowColormap (display.dpy, display.win, display.cmap);
224 }
225 
226 #if defined (commentout)
227 void
initfont()228 initfont ()
229 {
230   int i;
231   FILE *finf;
232   if ((finf = fopen (fontfile, "r")) == 0)
233     HandleError ("Can't open the font file", FATAL);
234   for (i = 0; i < 256 * 8; i++)
235     myfont[i] = fgetc (finf);
236   fclose (finf);
237 }
238 #endif
239 
240 void
Fgl_setfontcolors(int bg,int fg)241 Fgl_setfontcolors (int bg, int fg)
242 {
243   text_fg = fg;
244   text_bg = bg;
245 }
246 
247 void
Fgl_setfont(int fw,int fh,void * fp)248 Fgl_setfont (int fw, int fh, void *fp)
249 {
250   open_font = fp;
251   open_font_height = fh;
252 }
253 
254 void
parse_xargs(int argc,char ** argv,char ** geometry)255 parse_xargs (int argc, char **argv, char **geometry)
256 {
257     int option;
258     extern char *optarg;
259 
260 #ifdef ALLOW_PIX_DOUBLING
261     char* option_string = "vbrndg:wR:G:B:D";
262 #else
263     char* option_string = "vbrng:wR:G:B:D";
264 #endif
265     while ((option = getopt (argc, argv, option_string)) != EOF) {
266 	switch (option)
267 	{
268 	case 'v':
269 	    verbose = TRUE;
270 	    break;
271 	case 'g':
272 	    *geometry = optarg;
273 	    break;
274 #ifdef ALLOW_PIX_DOUBLING
275 	case 'd':
276 	    pix_double = 1;
277 	    /* Fall through.  We are not allowed a border with pix doubling */
278 #endif
279 	case 'b':
280 	    borderx = 0;
281 	    bordery = 0;
282 	    break;
283 	case 'r':
284 	    borderx = BORDERX;
285 	    bordery = BORDERY;
286 	    break;
287 	case 'n':
288 	    no_init_help = TRUE;
289 	    break;
290 	case 'w':
291 	    gamma_correct_red = GAMMA_CORRECT_RED;
292 	    gamma_correct_green = GAMMA_CORRECT_GREEN;
293 	    gamma_correct_blue = GAMMA_CORRECT_BLUE;
294 	    break;
295 	case 'R':
296 	    sscanf (optarg, "%f", &gamma_correct_red);
297 	    break;
298 	case 'G':
299 	    sscanf (optarg, "%f", &gamma_correct_green);
300 	    break;
301 	case 'B':
302 	    sscanf (optarg, "%f", &gamma_correct_blue);
303 	    break;
304 	case 'D':
305 	    command_line_debug = 1;
306 	    break;
307 	}
308     }
309     if (verbose)
310 	printf (_("Version %s\n"), VERSION);
311     if (!(display.dpy = XOpenDisplay (display.dname)))
312     {
313 	printf (" Can't open the dispay!\n");
314 	HandleError ("Cannot open display.\n", FATAL);
315 	exit (-1);
316     }
317     /* Record the screen number and root window. */
318     display.screen = DefaultScreen (display.dpy);
319     display.root = RootWindow (display.dpy, display.screen);
320 
321     display.winW = WINWIDTH + borderx * 2 + pix_double * WINWIDTH;
322     display.winH = WINHEIGHT + bordery * 2 + pix_double * WINHEIGHT;
323     winX = (DisplayWidth (display.dpy, display.screen) - display.winW) / 2;
324     winY = (DisplayHeight (display.dpy, display.screen) - display.winH) / 2;
325     if (*geometry != NULL)
326 	XParseGeometry (*geometry, &winX, &winY, &display.winW, &display.winH);
327 }
328 
329 
330 void
Create_Window(char * geometry)331 Create_Window (char *geometry)
332 {
333     short q;
334     Visual *vid;
335     XSetWindowAttributes xswa;
336     XSizeHints sizehint;
337     XWMHints wmhints;
338     int depth;
339     unsigned char wname[256];	/* Window Name */
340     unsigned long vmask = CWEventMask | CWBackPixel | CWBackingStore;
341 
342     depth = DefaultDepth (display.dpy, display.screen);
343     xswa.event_mask = 0;
344     xswa.background_pixel = display.bg;
345     xswa.backing_store = Always;
346     debug_printf ("DefaultVisual id=%d bp-rgb=%d map-entries=%d\n",
347 		  (int) (*DefaultVisual (display.dpy, display.screen)).visualid,
348 		  (*DefaultVisual (display.dpy, display.screen)).bits_per_rgb,
349 		  (*DefaultVisual (display.dpy, display.screen)).map_entries);
350     vid = DefaultVisual (display.dpy, display.screen);
351     display.cmap
352 	    = XDefaultColormap (display.dpy, display.screen);
353     display.win = XCreateWindow (display.dpy, display.root,
354 				 winX, winY,
355 				 display.winW, display.winH, 0, depth,
356 				 InputOutput,	/* vid , */
357 				 DefaultVisual (display.dpy, display.screen),
358 				 /*      PseudoColor,  */
359 				 vmask, &xswa);
360 
361     sizehint.x = winX - 100;
362     sizehint.y = winY;
363     sizehint.width = display.winW;
364     sizehint.height = display.winH;
365     sizehint.min_width = display.winW;
366     sizehint.min_height = display.winH;
367     sizehint.max_width = display.winW;
368     sizehint.max_height = display.winH;
369     /* GCS FIX:  Be careful about resizing the opening screen */
370     /* WCK: Fixed.  We lock it now, and unlock it after the opening screen.
371        not gorgeous, but it works for now.  Still need to clean up.*/
372 #define NO_RESIZABLE_WINDOWS 1
373     if (geometry != NULL) {
374 #if defined (NO_RESIZABLE_WINDOWS)
375 	sizehint.flags = USPosition | USSize | PMinSize | PMaxSize;
376 #else
377 	sizehint.flags = USPosition | USSize | PMinSize;
378 #endif
379     } else {
380 #if defined (NO_RESIZABLE_WINDOWS)
381 	sizehint.flags = PPosition | PSize | PMinSize | PMaxSize;
382 #else
383 	sizehint.flags = PPosition | PSize | PMinSize;
384 #endif
385     }
386     XSetNormalHints (display.dpy, display.win, &sizehint);
387 
388     display.protocol_atom = XInternAtom (display.dpy, "WM_PROTOCOLS",
389 					 False);
390     display.kill_atom = XInternAtom (display.dpy, "WM_DELETE_WINDOW",
391 				     False);
392 
393     /* Title */
394     sprintf ((char *) wname,
395 	     _("xlincity, Version %s, "
396 	     "(Copyright) IJ Peters - copying policy GNU GPL"),
397 	     VERSION);
398     XChangeProperty (display.dpy, display.win,
399 		     XA_WM_NAME, XA_STRING, 8, PropModeReplace, wname,
400 		     strlen ((char *) wname));
401 
402     /* Window Manager Hints (This is supposed to make input work.) */
403     wmhints.flags = InputHint;
404     wmhints.input = True;
405     XSetWMHints (display.dpy, display.win, &wmhints);
406 
407     /* GCS - 2003/08/15 - Cygwin doesn't generate the MapEvent unless
408        the mask enabled before XMapWindow is called.  Therefore,
409        XSelectInput needs to be called before XMapWindow */
410     XSelectInput (display.dpy, display.win,
411 		  KeyPressMask | ButtonPressMask | ButtonReleaseMask
412 		  | ExposureMask | StructureNotifyMask);
413 
414     XMapWindow (display.dpy, display.win);
415 
416     for (q = 0; q < 256; q++)
417     {
418 	display.pixcolour_gc[q] = XCreateGC (display.dpy
419 					     ,display.win, 0, NULL);
420 	XSetForeground (display.dpy, display.pixcolour_gc[q], q);
421 	XSetBackground (display.dpy, display.pixcolour_gc[q],
422 			display.bg);
423 	XSetGraphicsExposures (display.dpy, display.pixcolour_gc[q],
424 			       False);
425     }
426 }
427 
428 void
unlock_window_size(void)429 unlock_window_size (void)
430 {
431     XSizeHints sizehint;
432 
433     sizehint.x = winX - 100;
434     sizehint.y = winY;
435     sizehint.width = display.winW;
436     sizehint.height = display.winH;
437     sizehint.min_width = display.winW;
438     sizehint.min_height = display.winH;
439     sizehint.max_width = display.winW;
440     sizehint.max_height = display.winH;
441 
442     sizehint.flags = USPosition | USSize | PMinSize;
443 
444     XSetNormalHints (display.dpy, display.win, &sizehint);
445 }
446 
447 
448 
449 void
HandleError(char * description,int degree)450 HandleError (char *description, int degree)
451 {
452   fprintf (stderr,
453 	   _("An error has occurred.  The description is below...\n"));
454   fprintf (stderr, "%s\n", description);
455 
456   if (degree == FATAL) {
457       fprintf (stderr, _("Program aborting...\n"));
458       exit (-1);
459     }
460 }
461 
462 void
Fgl_setpixel(int x,int y,int col)463 Fgl_setpixel (int x, int y, int col)
464 {
465     int i;
466     if (clipping_flag)
467 	if (x < xclip_x1 || x > xclip_x2 || y < xclip_y1 || y > xclip_y2)
468 	    return;
469     col &= 0xff;
470 
471     i = pixmap_index(x,y);
472 
473 #ifdef ALLOW_PIX_DOUBLING
474     if (pix_double) {
475 	if ((int) pixmap[i] != col)
476 	{
477 	    pixmap[i] = (unsigned char) col;
478 	    XFillRectangle (display.dpy, display.win,
479 			    display.pixcolour_gc[col], x * 2, y * 2, 2, 2);
480 	}
481     } else {
482 #endif
483 	if ((int) pixmap[i] != col)
484 	{
485 	    pixmap[i] = (unsigned char) col;
486 	    XDrawPoint (display.dpy, display.win,
487 			display.pixcolour_gc[col], x + borderx, y + bordery);
488 	}
489 #ifdef ALLOW_PIX_DOUBLING
490     }
491 #endif
492 }
493 
494 int
Fgl_getpixel(int x,int y)495 Fgl_getpixel (int x, int y)
496 {
497     return pixmap_getpixel (x, y);
498 }
499 
500 void
Fgl_hline(int x1,int y1,int x2,int col)501 Fgl_hline (int x1, int y1, int x2, int col)
502 {
503     col &= 0xff;
504     pixmap_hline (x1, y1, x2, col);
505 #ifdef ALLOW_PIX_DOUBLING
506     if (pix_double)
507 	XFillRectangle (display.dpy, display.win
508 			,display.pixcolour_gc[col], x1 * 2, y1 * 2
509 			,(x2 - x1) * 2 + 1, 2);
510     else
511 #endif
512 	XDrawLine (display.dpy, display.win
513 		   ,display.pixcolour_gc[col], x1 + borderx
514 		   ,y1 + bordery, x2 + borderx, y1 + bordery);
515 }
516 
517 void
Fgl_line(int x1,int y1,int dummy,int y2,int col)518 Fgl_line (int x1, int y1, int dummy, int y2, int col)
519      /* vertical lines only. */
520 {
521     col &= 0xff;
522     pixmap_vline (x1, y1, y2, col);
523 #ifdef ALLOW_PIX_DOUBLING
524     if (pix_double)
525 	XFillRectangle (display.dpy, display.win
526 			,display.pixcolour_gc[col], x1 * 2, y1 * 2
527 			,2, (y2 - y1) * 2 + 1);
528     else
529 #endif
530 	XDrawLine (display.dpy, display.win
531 		   ,display.pixcolour_gc[col], x1 + borderx
532 		   ,y1 + bordery, x1 + borderx, y2 + bordery);
533 }
534 
535 void
Fgl_write(int x,int y,char * s)536 Fgl_write (int x, int y, char *s)
537 {
538   int i;
539   for (i = 0; i < (int) (strlen (s)); i++)
540     my_x_putchar (x + i * 8, y, s[i]);
541 }
542 
543 void
open_write(int x,int y,char * s)544 open_write (int x, int y, char *s)
545 {
546   int i;
547   for (i = 0; i < (int) (strlen (s)); i++)
548     open_x_putchar (x + i * 8, y, s[i]);
549 }
550 
551 void
my_x_putchar(int xx,int yy,unsigned char c)552 my_x_putchar (int xx, int yy, unsigned char c)
553 {
554   int x, y, b;
555   for (y = 0; y < 8; y++)
556     {
557       b = main_font[c * 8 + y];
558       for (x = 0; x < 8; x++)
559 	{
560 	  if ((b & 0x80) == 0)
561 	    Fgl_setpixel (xx + x, yy + y, text_bg);
562 	  else
563 	    Fgl_setpixel (xx + x, yy + y, text_fg);
564 	  b = b << 1;
565 	}
566     }
567 }
568 
569 void
open_x_putchar(int xx,int yy,unsigned char c)570 open_x_putchar (int xx, int yy, unsigned char c)
571 {
572   int x, y, b;
573   for (y = 0; y < open_font_height; y++)
574     {
575       b = open_font[c * open_font_height + y];
576       for (x = 0; x < 8; x++)
577 	{
578 	  if ((b & 0x80) == 0)
579 	    Fgl_setpixel (xx + x, yy + y, text_bg);
580 	  else
581 	    Fgl_setpixel (xx + x, yy + y, text_fg);
582 	  b = b << 1;
583 	}
584     }
585 }
586 
587 void
Fgl_fillbox(int x1,int y1,int w,int h,int col)588 Fgl_fillbox (int x1, int y1, int w, int h, int col)
589 {
590     if (clipping_flag) {
591 	if (x1 < xclip_x1)
592 	    x1 = xclip_x1;
593 	if (x1 + w - 1 > xclip_x2)
594 	    w = xclip_x2 - x1 + 1;
595 	if (y1 < xclip_y1)
596 	    y1 = xclip_y1;
597 	if (y1 + h - 1 > xclip_y2)
598 	    h = xclip_y2 - y1 + 1;
599     }
600     col &= 0xff;
601     pixmap_fillbox (x1, y1, w, h, col);
602 
603 #ifdef ALLOW_PIX_DOUBLING
604     if (pix_double)
605 	XFillRectangle (display.dpy, display.win,
606 			display.pixcolour_gc[col], x1 * 2, y1 * 2, w * 2, h * 2);
607     else
608 #endif
609 	XFillRectangle (display.dpy, display.win,
610 			display.pixcolour_gc[col], x1 + borderx, y1 + bordery, w, h);
611 }
612 
613 #ifdef USE_IMAGES
614 
615 /*
616  * Instead of transfering a pixmap pixel by pixel, it is much more
617  * efficient to build an XImage in core and send it in one piece off
618  * to the X server.
619  *
620  * -- GB.
621  */
622 
623 static int
clamp(int x,int low,int high)624 clamp (int x, int low, int high)
625      /* clamp x to the interval [low, high] */
626 {
627   if (x < low)
628     x = low;
629   else if (x > high)
630     x = high;
631   return x;
632 }
633 
634 /*
635  * Copy the the sub-image (src_x, src_y, w, h) to the screen at
636  * (x0 + x1, y0 + y1).
637  * `src' is a pointer to the array of pixels.
638  * `bpl' is the width of that array.
639  * No clipping performed.
640  */
641 void
Fgl_putbox_low(Drawable dst,int x0,int y0,int x1,int y1,int w,int h,unsigned char * src,int bpl,int src_x,int src_y)642 Fgl_putbox_low (Drawable dst, int x0, int y0, int x1, int y1,
643 		int w, int h, unsigned char *src, int bpl,
644 		int src_x, int src_y)
645 {
646     XImage *im;
647     int x, y;
648 
649 #ifdef ALLOW_PIX_DOUBLING
650     const int pmult = pix_double ? 2 : 1;
651 #else
652     const int pmult = 1;
653 #endif
654 
655     im = XCreateImage (display.dpy, 0,	/* display and visual */
656 		       DefaultDepth (display.dpy, display.screen),	/* depth */
657 		       ZPixmap,	/* format */
658 		       0,		/* offset */
659 		       0,		/* data */
660 		       pmult * w, pmult * h,	/* width and height */
661 		       32, 0);	/* bitmap_pad and bytes_per_line */
662     /* XXX: assert is not the right way to check for errors - wck */
663     assert (im != 0);
664     im->data = (char *) malloc (im->bytes_per_line * pmult * h);
665     assert (im->data != 0);
666 
667     src += src_x + src_y * bpl;
668 
669     if (pmult == 1) {
670 	for (y = 0; y < h; y++)
671 	    for (x = 0; x < w; x++)
672 		XPutPixel (im, x, y, colour_table[src[x + y * bpl]]);
673     } else {
674 	for (y = 0; y < h; y++)
675 	    for (x = 0; x < w; x++)
676 	    {
677 		unsigned long c = colour_table[src[x + y * bpl]];
678 
679 		XPutPixel (im, 2 * x + 0, 2 * y + 0, c);
680 		XPutPixel (im, 2 * x + 0, 2 * y + 1, c);
681 		XPutPixel (im, 2 * x + 1, 2 * y + 0, c);
682 		XPutPixel (im, 2 * x + 1, 2 * y + 1, c);
683 	    }
684     }
685 
686     if (dst == display.win) {
687 	pixmap_putbox (src, 0, 0, bpl, x1, y1, w, h);
688     }
689 
690     XPutImage (display.dpy, dst, display.pixcolour_gc[0], im, 0, 0,
691 	       x0 + pmult * x1, y0 + pmult * y1, pmult * w, pmult * h);
692 
693     XDestroyImage (im);
694 }
695 
696 void
Fgl_putbox(int x,int y,int w,int h,void * buf)697 Fgl_putbox (int x, int y, int w, int h, void *buf)
698 {
699     int c_x0 = clipping_flag ? xclip_x1 : 0;
700     int c_x1 = clipping_flag ? xclip_x2 : display.winW - 1;
701     int c_y0 = clipping_flag ? xclip_y1 : 0;
702     int c_y1 = clipping_flag ? xclip_y2 : display.winH - 1;
703     int x1 = clamp (x, c_x0, c_x1);
704     int y1 = clamp (y, c_y0, c_y1);
705     int x2 = clamp (x + w, c_x0, c_x1 + 1);
706     int y2 = clamp (y + h, c_y0, c_y1 + 1);
707 
708     if (x2 > x1 && y2 > y1)
709 	Fgl_putbox_low (display.win, borderx, bordery, x1, y1, x2 - x1,
710 			y2 - y1, (unsigned char *) buf, w, x1 - x, y1 - y);
711 }
712 
713 #else
714 
715 void
Fgl_putbox(int x1,int y1,int w,int h,void * buf)716 Fgl_putbox (int x1, int y1, int w, int h, void *buf)
717 {
718     unsigned char *b;
719     b = (unsigned char *) buf;
720     int x, y;
721     for (y = y1; y < y1 + h; y++)
722 	for (x = x1; x < x1 + w; x++)
723 	    Fgl_setpixel (x, y, *(b++));
724 }
725 
726 #endif
727 
728 void
Fgl_getbox(int x1,int y1,int w,int h,void * buf)729 Fgl_getbox (int x1, int y1, int w, int h, void *buf)
730 {
731     unsigned char *b;
732     int x, y;
733     b = (unsigned char *) buf;
734     for (y = y1; y < y1 + h; y++)
735 	for (x = x1; x < x1 + w; x++)
736 	    *(b++) = (unsigned char) Fgl_getpixel (x, y);
737 }
738 
739 void
HandleEvent(XEvent * event)740 HandleEvent (XEvent * event)
741 {
742     XEvent loop_ev; /* for clearing the queue of events */
743 
744     switch (event->type)
745     {
746     case KeyPress:
747 	{
748 	    XKeyEvent *key_event = (XKeyEvent *) event;
749 	    char buf[128];
750 	    KeySym ks;
751 	    XComposeStatus status;
752 	    XLookupString (key_event, buf, 128, &ks, &status);
753 	    x_key_shifted = ShiftMask & key_event->state;
754 	    x_key_value = buf[0];
755 	    switch (ks) {
756 	    case XK_Left:
757 		x_key_value = 1;
758 		break;
759 	    case XK_Down:
760 		x_key_value = 2;
761 		break;
762 	    case XK_Up:
763 		x_key_value = 3;
764 		break;
765 	    case XK_Right:
766 		x_key_value = 4;
767 		break;
768 #if defined (commentout)
769 		/* GCS:  What the hell is this??? */
770 	    case 'C':
771 		if (!confine_pointer(-10,-10,200,200))
772 		    unconfine_pointer();
773 		break;
774 #endif
775 	    case XK_BackSpace:
776 	    case XK_Delete:
777 		x_key_value = 127;
778 		break;
779 	    }
780 	}
781 	break;
782 
783     case MotionNotify:
784 	{
785 	    XMotionEvent *ev = (XMotionEvent *) event;
786 
787 	    while (XCheckMaskEvent(display.dpy,PointerMotionMask,&loop_ev)) {
788 		ev = (XMotionEvent *) &loop_ev;
789 	    }
790 #ifdef DEBUG_X11_MOUSE
791 	    printf("pointer motion event\n");
792 #endif
793 	    if (ev->state & Button2Mask)
794 		drag_screen();
795 
796 	}
797 	break;
798 
799     case ButtonPress:
800 	{
801 	    XButtonEvent *ev = (XButtonEvent *) event;
802 	    if ((ev->state & ShiftMask) != 0)
803 		cs_mouse_shifted = 1;
804 	    else
805 		cs_mouse_shifted = 0;
806 #ifdef DEBUG_X11_MOUSE
807 	    printf("button press: ev->button = %d\n",ev->button);
808 #endif
809 #if defined (commentout)
810 	    mouse_button = ev->button;
811 #endif
812 	    switch (ev->button) {
813 	    case Button1:
814 		mouse_button = LC_MOUSE_LEFTBUTTON | LC_MOUSE_PRESS;
815 		break;
816 	    case Button2:
817 		mouse_button = LC_MOUSE_MIDDLEBUTTON | LC_MOUSE_PRESS;
818 		break;
819 	    case Button3:
820 		mouse_button = LC_MOUSE_RIGHTBUTTON | LC_MOUSE_PRESS;
821 		break;
822 
823 	    /* Wheel mouse support
824 	       Move further for Shift (in main.c: process_keystrokes() ),
825 	       left to right instead of up and down for Control */
826 
827 	    case Button4:  /* Up (3); Left (1) if Control */
828 		x_key_shifted = ShiftMask & ev->state;
829 		x_key_value = (ControlMask & ev->state) ? 1 : 3;
830 		break;
831 	    case Button5: /* Down (4); Right (2) if control */
832 		x_key_shifted = ShiftMask & ev->state;
833 		x_key_value = (ControlMask & ev->state) ? 4 : 2;
834 		break;
835 
836 	    /* XFree86-3 only supports 5 buttons, no Button6 or higher */
837 
838 	    }
839 	    cs_mouse_handler (mouse_button, 0, 0);
840 	    mouse_button = 0;
841 	}
842 	break;
843 
844     case ButtonRelease:
845 	{
846 	    XButtonEvent *ev = (XButtonEvent *) event;
847 	    mouse_button = ev->button;
848 #ifdef DEBUG_X11_MOUSE
849 	    printf("button release: ev->button = %d\n",ev->button);
850 #endif
851 	    switch (ev->button) {
852 	    case Button1:
853 		mouse_button = LC_MOUSE_LEFTBUTTON | LC_MOUSE_RELEASE;
854 		break;
855 	    case Button2:
856 		mouse_button = LC_MOUSE_MIDDLEBUTTON | LC_MOUSE_RELEASE;
857 		break;
858 	    case Button3:
859 		mouse_button = LC_MOUSE_RIGHTBUTTON | LC_MOUSE_RELEASE;
860 		break;
861 	    }
862 	    cs_mouse_handler (mouse_button, 0, 0);
863 	    mouse_button = 0;
864 	}
865 	break;
866 
867     case Expose:
868 	{
869 	    XExposeEvent *ev = (XExposeEvent *) event;
870 	    int gx1,gy1,gx2,gy2;
871 	    gx1 = ev->x;
872 	    gy1 = ev->y;
873 	    gx2 = ev->x + ev->width;
874 	    gy2 = ev->y + ev->height;
875 
876 	    /* Coalesce waiting exposes into single redraw */
877 	    while (XCheckMaskEvent(display.dpy,ExposureMask,&loop_ev)) {
878 	        ev = (XExposeEvent *) &loop_ev;
879 		gx1 = min_int (gx1,ev->x);
880 		gy1 = min_int (gy1,ev->y);
881 		gx2 = max_int (gx2,ev->x + ev->width);
882 		gy2 = max_int (gy2,ev->y + ev->height);
883 	    }
884 	    if (suppress_next_expose) {
885 		suppress_next_expose = 0;
886 		break;
887 	    }
888 	    refresh_screen (gx1,gy1,gx2,gy2);
889 	}
890 	break;
891 
892     case ConfigureNotify:
893 	{
894 	    XConfigureEvent *ev = (XConfigureEvent *) event;
895 
896 	    while (XCheckTypedEvent(display.dpy, ConfigureNotify, &loop_ev)) {
897 		ev = (XConfigureEvent *) &loop_ev;
898 	    }
899 	    resize_geometry (ev->width, ev->height);
900 	}
901 	break;
902     }
903     //fprintf(stderr,"Handler fell through, event->type = %d\n",event->type);
904 }
905 
906 #undef DEBUG_X11_MOUSE
907 
908 void
refresh_screen(int x1,int y1,int x2,int y2)909 refresh_screen (int x1, int y1, int x2, int y2)		/* bounds of refresh area */
910 {
911 #ifdef USE_IMAGES
912   int wx1 = x1-borderx < 0 ? 0 : x1-borderx;
913   int wy1 = y1-bordery < 0 ? 0 : y1-bordery;
914   int wx2 = x2-borderx > pixmap_width ? pixmap_width : x2-borderx;
915   int wy2 = y2-bordery > pixmap_height ? pixmap_height : y2-bordery;
916   if (wx2-wx1 <= 0 || wy2-wy1 <= 0) {
917       /* Note: the "< 0" part can happen for when x1 is in the right border,
918 	 or when y1 is in the left border. */
919       return;
920   }
921   Fgl_putbox_low (display.win, borderx, bordery, wx1, wy1,
922 		  wx2 - wx1, wy2 - wy1, (unsigned char*) pixmap,
923 		  pixmap_width, wx1, wy1);
924 #else
925   int x, y;
926 #ifdef ALLOW_PIX_DOUBLING
927   if (pix_double)
928     {
929       for (y = y1; y < y2; y++)
930 	for (x = x1; x < x2; x++)
931 	  XFillRectangle (display.dpy, display.win
932 			  ,display.pixcolour_gc[*(pixmap + x + y
933 			    * (640 + BORDERX)) & 0xff], x * 2, y * 2, 2, 2);
934     }
935   else
936     {
937 #endif
938       for (y = y1; y < y2; y++)
939 	for (x = x1; x < x2; x++)
940 	  XDrawPoint (display.dpy, display.win
941 		      ,display.pixcolour_gc[*(pixmap
942 				  + x + y * (640 + BORDERX)) & 0xff], x, y);
943 #ifdef ALLOW_PIX_DOUBLING
944     }
945 #endif /* ALLOW_PIX_DOUBLING */
946 #endif /* USE_IMAGES */
947 }
948 
949 void
Fgl_enableclipping(void)950 Fgl_enableclipping (void)
951 {
952   clipping_flag = 1;
953 }
954 
955 void
Fgl_setclippingwindow(int x1,int y1,int x2,int y2)956 Fgl_setclippingwindow (int x1, int y1, int x2, int y2)
957 {
958   xclip_x1 = x1;
959   xclip_y1 = y1;
960   xclip_x2 = x2;
961   xclip_y2 = y2;
962 }
963 
964 void
Fgl_disableclipping(void)965 Fgl_disableclipping (void)
966 {
967   clipping_flag = 0;
968 }
969 
970 void
do_call_event(int wait)971 do_call_event (int wait)
972 {
973   int dummy_int, x, y;
974   Window dummy_win;
975   XEvent xev;
976   if (XPending (display.dpy))
977     {
978       XNextEvent (display.dpy, &xev);
979       HandleEvent (&xev);
980     }
981   else if (wait)
982     lc_usleep (1000);
983 
984   /* WCK: this could possibly be better handled with a MotionEvent */
985   XQueryPointer (display.dpy, display.win, &dummy_win, &dummy_win
986 	      ,&dummy_int, &dummy_int, &x, &y, (unsigned int *) &dummy_int);
987 #ifdef ALLOW_PIX_DOUBLING
988   if (pix_double)
989     {
990       x /= 2;
991       y /= 2;
992     }
993   else
994     {
995 #endif
996       x -= borderx;
997       y -= bordery;
998 #ifdef ALLOW_PIX_DOUBLING
999     }
1000 #endif
1001   if (x != cs_mouse_x || y != cs_mouse_y)
1002   cs_mouse_handler (0, x - cs_mouse_x, y - cs_mouse_y);
1003   /* WCK: no longer passing mouse_button, 0 used instead. Presses are handled
1004    in the event loop */
1005 }
1006 
1007 void
call_event(void)1008 call_event (void)
1009 {
1010   do_call_event (0);
1011 }
1012 
1013 void
call_wait_event(void)1014 call_wait_event (void)
1015 {
1016   do_call_event (1);
1017 }
1018 
1019 int
lc_get_keystroke(void)1020 lc_get_keystroke (void)
1021 {
1022     int q;
1023     call_event ();
1024     q = x_key_value;
1025     x_key_value = 0;
1026     return q;
1027 }
1028 
1029 
1030 /* init_full_mouse is called just before the main client loop. */
1031 
1032 /* XXX: This needs a much better name */
1033 /* GCS: Yes it does, b/c it means something different for svgalib */
1034 void
init_x_mouse(void)1035 init_x_mouse (void)
1036 {
1037   XSelectInput (display.dpy, display.win,
1038 		KeyPressMask | ButtonPressMask | ButtonReleaseMask
1039 		| ExposureMask | StructureNotifyMask | ButtonMotionMask);
1040 }
1041 
1042 void
draw_border(void)1043 draw_border (void)
1044 {
1045     int col = TEXT_BG_COLOUR & 0xff;
1046     if (borderx > 0) {
1047 	XFillRectangle (display.dpy, display.win, display.pixcolour_gc[col],
1048 			0, bordery, borderx, display.winH - 2*bordery);
1049 	XFillRectangle (display.dpy, display.win, display.pixcolour_gc[col],
1050 			display.winW - borderx, bordery,
1051 			borderx, display.winH - 2*bordery);
1052     }
1053     if (bordery > 0) {
1054 	XFillRectangle (display.dpy, display.win, display.pixcolour_gc[col],
1055 			0, 0, display.winW, bordery);
1056 	XFillRectangle (display.dpy, display.win, display.pixcolour_gc[col],
1057 			0, display.winH - bordery, display.winW, bordery);
1058     }
1059 }
1060 
1061 #ifdef USE_PIXMAPS
1062 
1063 void
init_icon_pixmap(short type)1064 init_icon_pixmap (short type)
1065 {
1066     unsigned char *g;
1067 #if !defined USE_IMAGES
1068     int x, y;
1069 #endif
1070     int grp;
1071 
1072     grp = get_group_of_type(type);
1073 
1074 #ifdef ALLOW_PIX_DOUBLING
1075     if (pix_double) {
1076 	icon_pixmap[type]
1077 		= XCreatePixmap (display.dpy, display.win,
1078 				 main_groups[grp].size * 16 * 2,
1079 				 main_groups[grp].size * 16 * 2,
1080 				 DefaultDepth (display.dpy,
1081 					       display.screen));
1082     } else {
1083 #endif
1084 	icon_pixmap[type]
1085 		= XCreatePixmap (display.dpy, display.win,
1086 				 main_groups[grp].size * 16,
1087 				 main_groups[grp].size * 16,
1088 				 DefaultDepth (display.dpy,
1089 					       display.screen));
1090 #ifdef ALLOW_PIX_DOUBLING
1091     }
1092 #endif
1093 
1094     g = (unsigned char *) main_types[type].graphic;
1095 
1096 #ifdef USE_IMAGES
1097     Fgl_putbox_low (icon_pixmap[type],
1098 		    0, 0, 0, 0, main_groups[grp].size * 16,
1099 		    main_groups[grp].size * 16,
1100 		    g, main_groups[grp].size * 16,
1101 		    0, 0);
1102 #else
1103 #ifdef ALLOW_PIX_DOUBLING
1104     if (pix_double)	{
1105 	for (y = 0; y < main_groups[grp].size * 16; y++)
1106 	    for (x = 0; x < main_groups[grp].size * 16; x++)
1107 		XFillRectangle (display.dpy, icon_pixmap[type]
1108 				,display.pixcolour_gc[*(g++)]
1109 				,x * 2, y * 2, 2, 2);
1110     } else {
1111 #endif
1112 	for (y = 0; y < main_groups[grp].size * 16; y++)
1113 	    for (x = 0; x < main_groups[grp].size * 16; x++)
1114 		XDrawPoint (display.dpy, icon_pixmap[type]
1115 			    ,display.pixcolour_gc[*(g++)], x, y);
1116 #ifdef ALLOW_PIX_DOUBLING
1117     }
1118 #endif /* ALLOW_PIX_DOUBLING */
1119 #endif /* USE_IMAGES */
1120 }
1121 
1122 #endif /* USE_PIXMAPS */
1123