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